]> oss.titaniummirror.com Git - msp430-gcc.git/blobdiff - gcc/config/sparc/sparc.c
Imported gcc-4.4.3
[msp430-gcc.git] / gcc / config / sparc / sparc.c
index c23cbef1be529327fb22007f1d3630ccffb69938..d007ce5515ecb67c11bd8f20a16006409544026f 100644 (file)
@@ -1,35 +1,38 @@
-/* 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 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   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)
+the Free Software Foundation; either version 3, 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
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "real.h"
 #include "insn-config.h"
+#include "insn-codes.h"
 #include "conditions.h"
 #include "output.h"
 #include "insn-attr.h"
@@ -37,7 +40,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"
@@ -45,42 +47,242 @@ Boston, MA 02111-1307, USA.  */
 #include "debug.h"
 #include "target.h"
 #include "target-def.h"
+#include "cfglayout.h"
+#include "gimple.h"
+#include "langhooks.h"
+#include "params.h"
+#include "df.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 */
+};
+
+static const
+struct processor_costs niagara_costs = {
+  COSTS_N_INSNS (3), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (3), /* int zeroed load */
+  COSTS_N_INSNS (9), /* float load */
+  COSTS_N_INSNS (8), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (8), /* fadd, fsub */
+  COSTS_N_INSNS (26), /* fcmp */
+  COSTS_N_INSNS (8), /* fmov, fmovr */
+  COSTS_N_INSNS (29), /* fmul */
+  COSTS_N_INSNS (54), /* fdivs */
+  COSTS_N_INSNS (83), /* fdivd */
+  COSTS_N_INSNS (100), /* fsqrts - not implemented in hardware */
+  COSTS_N_INSNS (100), /* fsqrtd - not implemented in hardware */
+  COSTS_N_INSNS (11), /* imul */
+  COSTS_N_INSNS (11), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (72), /* idiv */
+  COSTS_N_INSNS (72), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+};
+
+static const
+struct processor_costs niagara2_costs = {
+  COSTS_N_INSNS (3), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (3), /* int zeroed load */
+  COSTS_N_INSNS (3), /* float load */
+  COSTS_N_INSNS (6), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (6), /* fadd, fsub */
+  COSTS_N_INSNS (6), /* fcmp */
+  COSTS_N_INSNS (6), /* fmov, fmovr */
+  COSTS_N_INSNS (6), /* fmul */
+  COSTS_N_INSNS (19), /* fdivs */
+  COSTS_N_INSNS (33), /* fdivd */
+  COSTS_N_INSNS (19), /* fsqrts */
+  COSTS_N_INSNS (33), /* fsqrtd */
+  COSTS_N_INSNS (5), /* imul */
+  COSTS_N_INSNS (5), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (31), /* idiv, average of 12 - 41 cycle range */
+  COSTS_N_INSNS (31), /* idivX, average of 12 - 41 cycle range */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+};
 
-/* 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;
 
-/* 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;
+/* The alias set for prologue/epilogue register save/restore.  */
+static GTY(()) alias_set_type sparc_sr_alias_set;
 
-/* Coordinate with the md file wrt special insns created by
-   sparc_nonflat_function_epilogue.  */
-bool sparc_emitting_epilogue;
+/* The alias set for the structure return value.  */
+static GTY(()) alias_set_type struct_value_alias_set;
 
-#ifdef LEAF_REGISTERS
+/* Save the operands last given to a compare for use when we
+   generate a scc or bcc insn.  */
+rtx sparc_compare_op0, sparc_compare_op1, sparc_compare_emitted;
 
 /* Vector to say how input registers are mapped to output registers.
    HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to
@@ -119,76 +321,116 @@ char sparc_leaf_regs[] =
   1, 1, 1, 1, 1, 1, 1, 1,
   1, 1, 1, 1, 1};
 
-#endif
+struct machine_function GTY(())
+{
+  /* Some local-dynamic TLS symbol name.  */
+  const char *some_ld_name;
 
-/* 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 int ultrasparc_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 void sparc_add_gc_roots    PARAMS ((void));
-static void mark_ultrasparc_pipeline_state 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 ultra_cmove_results_ready_p PARAMS ((rtx));
-static int ultra_fpmode_conflict_exists PARAMS ((enum machine_mode));
-static rtx *ultra_find_type PARAMS ((int, rtx *, int));
-static void ultra_build_types_avail PARAMS ((rtx *, int));
-static void ultra_flush_pipeline PARAMS ((void));
-static void ultra_rescan_pipeline_state PARAMS ((rtx *, 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));
+  /* True if the current function is leaf and uses only leaf regs,
+     so that the SPARC leaf function optimization can be applied.
+     Private version of current_function_uses_only_leaf_regs, see
+     sparc_expand_prologue for the rationale.  */
+  int leaf_function_p;
+
+  /* True if the data calculated by sparc_expand_prologue are valid.  */
+  bool prologue_data_valid_p;
+};
+
+#define sparc_leaf_function_p  cfun->machine->leaf_function_p
+#define sparc_prologue_data_valid_p  cfun->machine->prologue_data_valid_p
+
+/* Register we pretend to think the frame pointer is allocated to.
+   Normally, this is %fp, but if we are in a leaf procedure, this
+   is %sp+"something".  We record "something" separately as it may
+   be too big for reg+constant addressing.  */
+static rtx frame_base_reg;
+static HOST_WIDE_INT frame_base_offset;
+
+/* 1 if the next opcode is to be specially indented.  */
+int sparc_indent_opcode = 0;
+
+static bool sparc_handle_option (size_t, const char *, int);
+static void sparc_init_modes (void);
+static void scan_record_type (tree, int *, int *, int *);
+static int function_arg_slotno (const CUMULATIVE_ARGS *, enum machine_mode,
+                               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 emit_pic_helper (void);
+static void load_pic_register (bool);
+static int save_or_restore_regs (int, int, rtx, int, int);
+static void emit_save_or_restore_regs (int);
+static void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT);
+static void sparc_asm_function_epilogue (FILE *, HOST_WIDE_INT);
 #ifdef OBJECT_FORMAT_ELF
-static void sparc_elf_asm_named_section PARAMS ((const char *, unsigned int));
+static void sparc_elf_asm_named_section (const char *, unsigned int, tree);
+#endif
+
+static int sparc_adjust_cost (rtx, rtx, rtx, int);
+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_init_builtins (void);
+static void sparc_vis_init_builtins (void);
+static rtx sparc_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
+static tree sparc_fold_builtin (tree, tree, bool);
+static int sparc_vis_mul8x16 (int, int);
+static tree sparc_handle_vis_mul8x16 (int, tree, tree, tree);
+static void sparc_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
+                                  HOST_WIDE_INT, tree);
+static bool sparc_can_output_mi_thunk (const_tree, HOST_WIDE_INT,
+                                      HOST_WIDE_INT, const_tree);
+static struct machine_function * sparc_init_machine_status (void);
+static bool sparc_cannot_force_const_mem (rtx);
+static rtx sparc_tls_get_addr (void);
+static rtx sparc_tls_got (void);
+static const char *get_some_local_dynamic_name (void);
+static int get_some_local_dynamic_name_1 (rtx *, void *);
+static bool sparc_rtx_costs (rtx, int, int, int *, bool);
+static bool sparc_promote_prototypes (const_tree);
+static rtx sparc_struct_value_rtx (tree, int);
+static bool sparc_return_in_memory (const_tree, const_tree);
+static bool sparc_strict_argument_naming (CUMULATIVE_ARGS *);
+static void sparc_va_start (tree, rtx);
+static tree sparc_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
+static bool sparc_vector_mode_supported_p (enum machine_mode);
+static bool sparc_tls_referenced_p (rtx);
+static rtx legitimize_tls_address (rtx);
+static rtx legitimize_pic_address (rtx, rtx);
+static bool sparc_pass_by_reference (CUMULATIVE_ARGS *,
+                                    enum machine_mode, const_tree, bool);
+static int sparc_arg_partial_bytes (CUMULATIVE_ARGS *,
+                                   enum machine_mode, tree, bool);
+static void sparc_dwarf_handle_frame_unspec (const char *, rtx, int);
+static void sparc_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
+static void sparc_file_end (void);
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+static const char *sparc_mangle_type (const_tree);
+#endif
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+const struct attribute_spec sparc_attribute_table[];
 #endif
-static void ultrasparc_sched_reorder PARAMS ((FILE *, int, rtx *, int));
-static int ultrasparc_variable_issue PARAMS ((rtx));
-static void ultrasparc_sched_init PARAMS ((void));
-
-static int sparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
-static int sparc_issue_rate PARAMS ((void));
-static int sparc_variable_issue PARAMS ((FILE *, int, rtx, int));
-static void sparc_sched_init PARAMS ((FILE *, int, int));
-static int sparc_sched_reorder PARAMS ((FILE *, int, rtx *, int *, int));
-
-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 *));
 \f
 /* Option handling.  */
 
-/* Code model option as passed by user.  */
-const char *sparc_cmodel_string;
 /* Parsed value.  */
 enum cmodel sparc_cmodel;
 
@@ -205,7 +447,10 @@ struct sparc_cpu_select sparc_select[] =
 
 /* CPU type.  This is set from TARGET_CPU_DEFAULT and -m{cpu,tune}=xxx.  */
 enum processor_type sparc_cpu;
-\f
+
+/* Whether\fan FPU option was specified.  */
+static bool fpu_option_set = false;
+
 /* Initialize the GCC target structure.  */
 
 /* The sparc default is to use .half rather than .short for aligned
@@ -229,28 +474,155 @@ 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
 #undef TARGET_SCHED_ISSUE_RATE
 #define TARGET_SCHED_ISSUE_RATE sparc_issue_rate
-#undef TARGET_SCHED_VARIABLE_ISSUE
-#define TARGET_SCHED_VARIABLE_ISSUE sparc_variable_issue
 #undef TARGET_SCHED_INIT
 #define TARGET_SCHED_INIT sparc_sched_init
-#undef TARGET_SCHED_REORDER
-#define TARGET_SCHED_REORDER sparc_sched_reorder
+#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
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS sparc_init_builtins
+
+#undef TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN sparc_expand_builtin
+#undef TARGET_FOLD_BUILTIN
+#define TARGET_FOLD_BUILTIN sparc_fold_builtin
+
+#if TARGET_TLS
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS true
+#endif
+
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM sparc_cannot_force_const_mem
+
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK sparc_output_mi_thunk
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK sparc_can_output_mi_thunk
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS sparc_rtx_costs
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST hook_int_rtx_bool_0
+
+/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a
+   no-op for TARGET_ARCH32 this is ok.  Otherwise we'd need to add a runtime
+   test for this value.  */
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
+
+/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a
+   no-op for TARGET_ARCH32 this is ok.  Otherwise we'd need to add a runtime
+   test for this value.  */
+#undef TARGET_PROMOTE_FUNCTION_RETURN
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
+
+#undef TARGET_PROMOTE_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_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES sparc_arg_partial_bytes
+
+#undef TARGET_EXPAND_BUILTIN_SAVEREGS
+#define TARGET_EXPAND_BUILTIN_SAVEREGS sparc_builtin_saveregs
+#undef TARGET_STRICT_ARGUMENT_NAMING
+#define TARGET_STRICT_ARGUMENT_NAMING sparc_strict_argument_naming
+
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START sparc_va_start
+#undef TARGET_GIMPLIFY_VA_ARG_EXPR
+#define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg
+
+#undef TARGET_VECTOR_MODE_SUPPORTED_P
+#define TARGET_VECTOR_MODE_SUPPORTED_P sparc_vector_mode_supported_p
+
+#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
+#define TARGET_DWARF_HANDLE_FRAME_UNSPEC sparc_dwarf_handle_frame_unspec
+
+#ifdef SUBTARGET_INSERT_ATTRIBUTES
+#undef TARGET_INSERT_ATTRIBUTES
+#define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
+#endif
+
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE sparc_attribute_table
+#endif
+
+#undef TARGET_RELAXED_ORDERING
+#define TARGET_RELAXED_ORDERING SPARC_RELAXED_ORDERING
+
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION sparc_handle_option
+
+#if TARGET_GNU_TLS && defined(HAVE_AS_SPARC_UA_PCREL)
+#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
+#define TARGET_ASM_OUTPUT_DWARF_DTPREL sparc_output_dwarf_dtprel
+#endif
+
+#undef TARGET_ASM_FILE_END
+#define TARGET_ASM_FILE_END sparc_file_end
+
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+#undef TARGET_MANGLE_TYPE
+#define TARGET_MANGLE_TYPE sparc_mangle_type
+#endif
 
 struct gcc_target targetm = TARGET_INITIALIZER;
-\f
+
+/* Implement TARGET_HANDLE_OPTION.  */
+
+static bool
+sparc_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
+{
+  switch (code)
+    {
+    case OPT_mfpu:
+    case OPT_mhard_float:
+    case OPT_msoft_float:
+      fpu_option_set = true;
+      break;
+
+    case OPT_mcpu_:
+      sparc_select[1].string = arg;
+      break;
+
+    case OPT_mtune_:
+      sparc_select[2].string = arg;
+      break;
+    }
+
+  return true;
+}
+
 /* Validate and override various options, and do some machine dependent
    initialization.  */
 
 void
-sparc_override_options ()
+sparc_override_options (void)
 {
   static struct code_model {
     const char *const name;
@@ -279,6 +651,9 @@ sparc_override_options ()
     { TARGET_CPU_supersparc, "supersparc" },
     { TARGET_CPU_v9, "v9" },
     { TARGET_CPU_ultrasparc, "ultrasparc" },
+    { TARGET_CPU_ultrasparc3, "ultrasparc3" },
+    { TARGET_CPU_niagara, "niagara" },
+    { TARGET_CPU_niagara2, "niagara2" },
     { 0, 0 }
   };
   const struct cpu_default *def;
@@ -311,6 +686,12 @@ sparc_override_options ()
     /* Although insns using %y are deprecated, it is a clear win on current
        ultrasparcs.  */
                                                    |MASK_DEPRECATED_V8_INSNS},
+    /* TI ultrasparc III */
+    /* ??? Check if %y issue still holds true in ultra3.  */
+    { "ultrasparc3", PROCESSOR_ULTRASPARC3, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS},
+    /* UltraSPARC T1 */
+    { "niagara", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS},
+    { "niagara2", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9},
     { 0, 0, 0, 0 }
   };
   const struct cpu_table *cpu;
@@ -355,14 +736,13 @@ sparc_override_options ()
        error ("-mcmodel= is not supported on 32 bit systems");
     }
 
-  fpu = TARGET_FPU; /* save current -mfpu status */
+  fpu = target_flags & MASK_FPU; /* save current -mfpu status */
 
   /* Set the default CPU.  */
   for (def = &cpu_default[0]; def->name; ++def)
     if (def->cpu == TARGET_CPU_DEFAULT)
       break;
-  if (! def->name)
-    abort ();
+  gcc_assert (def->name);
   sparc_select[0].string = def->name;
 
   for (sel = &sparc_select[0]; sel->name; ++sel)
@@ -389,13 +769,9 @@ sparc_override_options ()
     }
 
   /* If -mfpu or -mno-fpu was explicitly used, don't override with
-     the processor default.  Clear MASK_FPU_SET to avoid confusing
-     the reverse mapping from switch values to names.  */
-  if (TARGET_FPU_SET)
-    {
-      target_flags = (target_flags & ~MASK_FPU) | fpu;
-      target_flags &= ~MASK_FPU_SET;
-    }
+     the processor default.  */
+  if (fpu_option_set)
+    target_flags = (target_flags & ~MASK_FPU) | fpu;
 
   /* Don't allow -mvis if FPU is disabled.  */
   if (! TARGET_FPU)
@@ -423,7 +799,11 @@ sparc_override_options ()
     target_flags &= ~MASK_STACK_BIAS;
     
   /* Supply a default value for align_functions.  */
-  if (align_functions == 0 && sparc_cpu == PROCESSOR_ULTRASPARC)
+  if (align_functions == 0
+      && (sparc_cpu == PROCESSOR_ULTRASPARC
+         || sparc_cpu == PROCESSOR_ULTRASPARC3
+         || sparc_cpu == PROCESSOR_NIAGARA
+         || sparc_cpu == PROCESSOR_NIAGARA2))
     align_functions = 32;
 
   /* Validate PCC_STRUCT_RETURN.  */
@@ -437,80 +817,99 @@ sparc_override_options ()
   /* Do various machine dependent initializations.  */
   sparc_init_modes ();
 
-  /* Register global variables with the garbage collector.  */
-  sparc_add_gc_roots ();
+  /* Acquire unique alias sets for our private stuff.  */
+  sparc_sr_alias_set = new_alias_set ();
+  struct_value_alias_set = new_alias_set ();
+
+  /* Set up function hooks.  */
+  init_machine_status = sparc_init_machine_status;
+
+  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;
+    case PROCESSOR_NIAGARA:
+      sparc_costs = &niagara_costs;
+      break;
+    case PROCESSOR_NIAGARA2:
+      sparc_costs = &niagara2_costs;
+      break;
+    };
+
+#ifdef TARGET_DEFAULT_LONG_DOUBLE_128
+  if (!(target_flags_explicit & MASK_LONG_DOUBLE_128))
+    target_flags |= MASK_LONG_DOUBLE_128;
+#endif
+
+  if (!PARAM_SET_P (PARAM_SIMULTANEOUS_PREFETCHES))
+    set_param_value ("simultaneous-prefetches",
+                    ((sparc_cpu == PROCESSOR_ULTRASPARC
+                      || sparc_cpu == PROCESSOR_NIAGARA
+                      || sparc_cpu == PROCESSOR_NIAGARA2)
+                     ? 2
+                     : (sparc_cpu == PROCESSOR_ULTRASPARC3
+                        ? 8 : 3)));
+  if (!PARAM_SET_P (PARAM_L1_CACHE_LINE_SIZE))
+    set_param_value ("l1-cache-line-size", 
+                    ((sparc_cpu == PROCESSOR_ULTRASPARC
+                      || sparc_cpu == PROCESSOR_ULTRASPARC3
+                      || sparc_cpu == PROCESSOR_NIAGARA
+                      || sparc_cpu == PROCESSOR_NIAGARA2)
+                     ? 64 : 32));
 }
 \f
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+/* 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);
 }
 
-\f
-/* Operand constraints.  */
-
-/* Return non-zero only if OP is a register of mode MODE,
-   or const0_rtx.  */
-
-int
-reg_or_0_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  if (register_operand (op, mode))
-    return 1;
-  if (op == const0_rtx)
-    return 1;
-  if (GET_MODE (op) == VOIDmode && GET_CODE (op) == CONST_DOUBLE
-      && CONST_DOUBLE_HIGH (op) == 0
-      && CONST_DOUBLE_LOW (op) == 0)
-    return 1;
-  if (fp_zero_operand (op, mode))
-    return 1;
-  return 0;
-}
-
-/* Nonzero if OP is a floating point value with value 0.0.  */
-
-int
-fp_zero_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  if (GET_MODE_CLASS (GET_MODE (op)) != MODE_FLOAT)
-    return 0;
-  return op == CONST0_RTX (mode);
-}
-
-/* Nonzero if OP is a register operand in floating point register.  */
-
-int
-fp_register_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  if (! register_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  return GET_CODE (op) == REG && SPARC_FP_REG_P (REGNO (op));
-}
-
 /* Nonzero if OP is a floating point constant which can
    be loaded into an integer register using a single
    sethi instruction.  */
 
 int
-fp_sethi_p (op)
-     rtx op;
+fp_sethi_p (rtx op)
 {
   if (GET_CODE (op) == CONST_DOUBLE)
     {
@@ -518,12 +917,8 @@ fp_sethi_p (op)
       long i;
 
       REAL_VALUE_FROM_CONST_DOUBLE (r, op);
-      if (REAL_VALUES_EQUAL (r, dconst0) &&
-         ! REAL_VALUE_MINUS_ZERO (r))
-       return 0;
       REAL_VALUE_TO_TARGET_SINGLE (r, i);
-      if (SPARC_SETHI_P (i))
-       return 1;
+      return !SPARC_SIMM13_P (i) && SPARC_SETHI_P (i);
     }
 
   return 0;
@@ -534,8 +929,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)
     {
@@ -543,12 +937,8 @@ fp_mov_p (op)
       long i;
 
       REAL_VALUE_FROM_CONST_DOUBLE (r, op);
-      if (REAL_VALUES_EQUAL (r, dconst0) &&
-         ! REAL_VALUE_MINUS_ZERO (r))
-       return 0;
       REAL_VALUE_TO_TARGET_SINGLE (r, i);
-      if (SPARC_SIMM13_P (i))
-       return 1;
+      return SPARC_SIMM13_P (i);
     }
 
   return 0;
@@ -559,8 +949,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
@@ -571,1429 +960,781 @@ fp_high_losum_p (op)
       long i;
 
       REAL_VALUE_FROM_CONST_DOUBLE (r, op);
-      if (REAL_VALUES_EQUAL (r, dconst0) &&
-         ! REAL_VALUE_MINUS_ZERO (r))
-       return 0;
       REAL_VALUE_TO_TARGET_SINGLE (r, i);
-      if (! SPARC_SETHI_P (i)
-          && ! SPARC_SIMM13_P (i))
-       return 1;
+      return !SPARC_SIMM13_P (i) && !SPARC_SETHI_P (i);
     }
 
   return 0;
 }
 
-/* Nonzero if OP is an integer register.  */
-
-int
-intreg_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return (register_operand (op, SImode)
-         || (TARGET_ARCH64 && register_operand (op, DImode)));
-}
-
-/* Nonzero if OP is a floating point condition code register.  */
-
-int
-fcc_reg_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  /* This can happen when recog is called from combine.  Op may be a MEM.
-     Fail instead of calling abort in this case.  */
-  if (GET_CODE (op) != REG)
-    return 0;
-
-  if (mode != VOIDmode && mode != GET_MODE (op))
-    return 0;
-  if (mode == VOIDmode
-      && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
-    return 0;
-
-#if 0  /* ??? ==> 1 when %fcc0-3 are pseudos first.  See gen_compare_reg().  */
-  if (reg_renumber == 0)
-    return REGNO (op) >= FIRST_PSEUDO_REGISTER;
-  return REGNO_OK_FOR_CCFP_P (REGNO (op));
-#else
-  return (unsigned) REGNO (op) - SPARC_FIRST_V9_FCC_REG < 4;
-#endif
-}
-
-/* Nonzero if OP is a floating point condition code fcc0 register.  */
+/* Expand a move instruction.  Return true if all work is done.  */
 
-int
-fcc0_reg_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+bool
+sparc_expand_move (enum machine_mode mode, rtx *operands)
 {
-  /* This can happen when recog is called from combine.  Op may be a MEM.
-     Fail instead of calling abort in this case.  */
-  if (GET_CODE (op) != REG)
-    return 0;
-
-  if (mode != VOIDmode && mode != GET_MODE (op))
-    return 0;
-  if (mode == VOIDmode
-      && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
-    return 0;
-
-  return REGNO (op) == SPARC_FCC_REG;
-}
+  /* Handle sets of MEM first.  */
+  if (GET_CODE (operands[0]) == MEM)
+    {
+      /* 0 is a register (or a pair of registers) on SPARC.  */
+      if (register_or_zero_operand (operands[1], mode))
+       return false;
 
-/* Nonzero if OP is an integer or floating point condition code register.  */
+      if (!reload_in_progress)
+       {
+         operands[0] = validize_mem (operands[0]);
+         operands[1] = force_reg (mode, operands[1]);
+       }
+    }
 
-int
-icc_or_fcc_reg_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  if (GET_CODE (op) == REG && REGNO (op) == SPARC_ICC_REG)
+  /* Fixup TLS cases.  */
+  if (TARGET_HAVE_TLS
+      && CONSTANT_P (operands[1])
+      && sparc_tls_referenced_p (operands [1]))
     {
-      if (mode != VOIDmode && mode != GET_MODE (op))
-       return 0;
-      if (mode == VOIDmode
-         && GET_MODE (op) != CCmode && GET_MODE (op) != CCXmode)
-       return 0;
-      return 1;
+      operands[1] = legitimize_tls_address (operands[1]);
+      return false;
     }
 
-  return fcc_reg_operand (op, mode);
-}
+  /* Fixup PIC cases.  */
+  if (flag_pic && CONSTANT_P (operands[1]))
+    {
+      if (pic_address_needs_scratch (operands[1]))
+       operands[1] = legitimize_pic_address (operands[1], NULL_RTX);
 
-/* 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)));
-}
+      /* VxWorks does not impose a fixed gap between segments; the run-time
+        gap can be different from the object-file gap.  We therefore can't
+        assume X - _GLOBAL_OFFSET_TABLE_ is a link-time constant unless we
+        are absolutely sure that X is in the same segment as the GOT.
+        Unfortunately, the flexibility of linker scripts means that we
+        can't be sure of that in general, so assume that _G_O_T_-relative
+        accesses are never valid on VxWorks.  */
+      if (GET_CODE (operands[1]) == LABEL_REF && !TARGET_VXWORKS_RTP)
+       {
+         if (mode == SImode)
+           {
+             emit_insn (gen_movsi_pic_label_ref (operands[0], operands[1]));
+             return true;
+           }
 
-/* Call insn on SPARC can take a PC-relative constant address, or any regular
-   memory address.  */
+         if (mode == DImode)
+           {
+             gcc_assert (TARGET_ARCH64);
+             emit_insn (gen_movdi_pic_label_ref (operands[0], operands[1]));
+             return true;
+           }
+       }
 
-int
-call_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  if (GET_CODE (op) != MEM)
-    abort ();
-  op = XEXP (op, 0);
-  return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));
-}
+      if (symbolic_operand (operands[1], mode))
+       {
+         operands[1] = legitimize_pic_address (operands[1],
+                                               reload_in_progress
+                                               ? operands[0] : NULL_RTX);
+         return false;
+       }
+    }
 
-int
-call_operand_address (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));
-}
+  /* If we are trying to toss an integer constant into FP registers,
+     or loading a FP or vector constant, force it into memory.  */
+  if (CONSTANT_P (operands[1])
+      && REG_P (operands[0])
+      && (SPARC_FP_REG_P (REGNO (operands[0]))
+         || SCALAR_FLOAT_MODE_P (mode)
+         || VECTOR_MODE_P (mode)))
+    {
+      /* emit_group_store will send such bogosity to us when it is
+         not storing directly into memory.  So fix this up to avoid
+         crashes in output_constant_pool.  */
+      if (operands [1] == const0_rtx)
+       operands[1] = CONST0_RTX (mode);
 
-/* Returns 1 if OP is either a symbol reference or a sum of a symbol
-   reference and a constant.  */
+      /* We can clear FP registers if TARGET_VIS, and always other regs.  */
+      if ((TARGET_VIS || REGNO (operands[0]) < SPARC_FIRST_FP_REG)
+         && const_zero_operand (operands[1], mode))
+       return false;
 
-int
-symbolic_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
-{
-  enum machine_mode omode = GET_MODE (op);
+      if (REGNO (operands[0]) < SPARC_FIRST_FP_REG
+         /* We are able to build any SF constant in integer registers
+            with at most 2 instructions.  */
+         && (mode == SFmode
+             /* And any DF constant in integer registers.  */
+             || (mode == DFmode
+                 && (reload_completed || reload_in_progress))))
+       return false;
 
-  if (omode != mode && omode != VOIDmode && mode != VOIDmode)
-    return 0;
+      operands[1] = force_const_mem (mode, operands[1]);
+      if (!reload_in_progress)
+       operands[1] = validize_mem (operands[1]);
+      return false;
+    }
 
-  switch (GET_CODE (op))
+  /* Accept non-constants and valid constants unmodified.  */
+  if (!CONSTANT_P (operands[1])
+      || GET_CODE (operands[1]) == HIGH
+      || input_operand (operands[1], mode))
+    return false;
+
+  switch (mode)
     {
-    case SYMBOL_REF:
-    case LABEL_REF:
-      return 1;
+    case QImode:
+      /* All QImode constants require only one insn, so proceed.  */
+      break;
 
-    case CONST:
-      op = XEXP (op, 0);
-      return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
-              || GET_CODE (XEXP (op, 0)) == LABEL_REF)
-             && GET_CODE (XEXP (op, 1)) == CONST_INT);
+    case HImode:
+    case SImode:
+      sparc_emit_set_const32 (operands[0], operands[1]);
+      return true;
 
+    case DImode:
+      /* input_operand should have filtered out 32-bit mode.  */
+      sparc_emit_set_const64 (operands[0], operands[1]);
+      return true;
+    
     default:
-      return 0;
+      gcc_unreachable ();
     }
-}
 
-/* Return truth value of statement that OP is a symbolic memory
-   operand of mode MODE.  */
-
-int
-symbolic_memory_operand (op, mode)
-     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 false;
 }
 
-/* Return truth value of statement that OP is a LABEL_REF of mode MODE.  */
+/* Load OP1, a 32-bit constant, into OP0, a register.
+   We know it can't be done in one insn when we get
+   here, the move expander guarantees this.  */
 
-int
-label_ref_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+void
+sparc_emit_set_const32 (rtx op0, rtx op1)
 {
-  if (GET_CODE (op) != LABEL_REF)
-    return 0;
-  if (GET_MODE (op) != mode)
-    return 0;
-  return 1;
-}
+  enum machine_mode mode = GET_MODE (op0);
+  rtx temp;
 
-/* Return 1 if the operand is an argument used in generating pic references
-   in either the medium/low or medium/anywhere code models of sparc64.  */
+  if (reload_in_progress || reload_completed)
+    temp = op0;
+  else
+    temp = gen_reg_rtx (mode);
 
-int
-sp64_medium_pic_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  /* Check for (const (minus (symbol_ref:GOT)
-                             (const (minus (label) (pc))))).  */
-  if (GET_CODE (op) != CONST)
-    return 0;
-  op = XEXP (op, 0);
-  if (GET_CODE (op) != MINUS)
-    return 0;
-  if (GET_CODE (XEXP (op, 0)) != SYMBOL_REF)
-    return 0;
-  /* ??? Ensure symbol is GOT.  */
-  if (GET_CODE (XEXP (op, 1)) != CONST)
-    return 0;
-  if (GET_CODE (XEXP (XEXP (op, 1), 0)) != MINUS)
-    return 0;
-  return 1;
-}
+  if (GET_CODE (op1) == CONST_INT)
+    {
+      gcc_assert (!small_int_operand (op1, mode)
+                 && !const_high_operand (op1, mode));
 
-/* Return 1 if the operand is a data segment reference.  This includes
-   the readonly data segment, or in other words anything but the text segment.
-   This is needed in the medium/anywhere code model on v9.  These values
-   are accessed with EMBMEDANY_BASE_REG.  */
+      /* Emit them as real moves instead of a HIGH/LO_SUM,
+        this way CSE can see everything and reuse intermediate
+        values if it wants.  */
+      emit_insn (gen_rtx_SET (VOIDmode, temp,
+                             GEN_INT (INTVAL (op1)
+                               & ~(HOST_WIDE_INT)0x3ff)));
 
-int
-data_segment_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  switch (GET_CODE (op))
-    {
-    case SYMBOL_REF :
-      return ! SYMBOL_REF_FLAG (op);
-    case PLUS :
-      /* Assume canonical format of symbol + constant.
-        Fall through.  */
-    case CONST :
-      return data_segment_operand (XEXP (op, 0), VOIDmode);
-    default :
-      return 0;
+      emit_insn (gen_rtx_SET (VOIDmode,
+                             op0,
+                             gen_rtx_IOR (mode, temp,
+                                          GEN_INT (INTVAL (op1) & 0x3ff))));
+    }
+  else
+    {
+      /* A symbol, emit in the traditional way.  */
+      emit_insn (gen_rtx_SET (VOIDmode, temp,
+                             gen_rtx_HIGH (mode, op1)));
+      emit_insn (gen_rtx_SET (VOIDmode,
+                             op0, gen_rtx_LO_SUM (mode, temp, op1)));
     }
 }
 
-/* Return 1 if the operand is a text segment reference.
-   This is needed in the medium/anywhere code model on v9.  */
+/* Load OP1, a symbolic 64-bit constant, into OP0, a DImode register.
+   If TEMP is nonzero, we are forbidden to use any other scratch
+   registers.  Otherwise, we are allowed to generate them as needed.
 
-int
-text_segment_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+   Note that TEMP may have TImode if the code model is TARGET_CM_MEDANY
+   or TARGET_CM_EMBMEDANY (see the reload_indi and reload_outdi patterns).  */
+
+void
+sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
 {
-  switch (GET_CODE (op))
+  rtx temp1, temp2, temp3, temp4, temp5;
+  rtx ti_temp = 0;
+
+  if (temp && GET_MODE (temp) == TImode)
     {
-    case LABEL_REF :
-      return 1;
-    case SYMBOL_REF :
-      return SYMBOL_REF_FLAG (op);
-    case PLUS :
-      /* Assume canonical format of symbol + constant.
-        Fall through.  */
-    case CONST :
-      return text_segment_operand (XEXP (op, 0), VOIDmode);
-    default :
-      return 0;
+      ti_temp = temp;
+      temp = gen_rtx_REG (DImode, REGNO (temp));
     }
-}
 
-/* Return 1 if the operand is either a register or a memory operand that is
-   not symbolic.  */
+  /* SPARC-V9 code-model support.  */
+  switch (sparc_cmodel)
+    {
+    case CM_MEDLOW:
+      /* The range spanned by all instructions in the object is less
+        than 2^31 bytes (2GB) and the distance from any instruction
+        to the location of the label _GLOBAL_OFFSET_TABLE_ is less
+        than 2^31 bytes (2GB).
 
-int
-reg_or_nonsymb_mem_operand (op, mode)
-    register rtx op;
-    enum machine_mode mode;
-{
-  if (register_operand (op, mode))
-    return 1;
+        The executable must be in the low 4TB of the virtual address
+        space.
 
-  if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
-    return 1;
+        sethi  %hi(symbol), %temp1
+        or     %temp1, %lo(symbol), %reg  */
+      if (temp)
+       temp1 = temp;  /* op0 is allowed.  */
+      else
+       temp1 = gen_reg_rtx (DImode);
 
-  return 0;
-}
-
-int
-splittable_symbolic_memory_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  if (GET_CODE (op) != MEM)
-    return 0;
-  if (! symbolic_operand (XEXP (op, 0), Pmode))
-    return 0;
-  return 1;
-}
-
-int
-splittable_immediate_memory_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  if (GET_CODE (op) != MEM)
-    return 0;
-  if (! immediate_operand (XEXP (op, 0), Pmode))
-    return 0;
-  return 1;
-}
-
-/* Return truth value of whether OP is EQ or NE.  */
-
-int
-eq_or_neq (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
-}
-
-/* Return 1 if this is a comparison operator, but not an EQ, NE, GEU,
-   or LTU for non-floating-point.  We handle those specially.  */
-
-int
-normal_comp_operator (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  enum rtx_code code = GET_CODE (op);
-
-  if (GET_RTX_CLASS (code) != '<')
-    return 0;
-
-  if (GET_MODE (XEXP (op, 0)) == CCFPmode
-      || GET_MODE (XEXP (op, 0)) == CCFPEmode)
-    return 1;
+      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;
 
-  return (code != NE && code != EQ && code != GEU && code != LTU);
-}
+    case CM_MEDMID:
+      /* The range spanned by all instructions in the object is less
+        than 2^31 bytes (2GB) and the distance from any instruction
+        to the location of the label _GLOBAL_OFFSET_TABLE_ is less
+        than 2^31 bytes (2GB).
 
-/* Return 1 if this is a comparison operator.  This allows the use of
-   MATCH_OPERATOR to recognize all the branch insns.  */
+        The executable must be in the low 16TB of the virtual address
+        space.
 
-int
-noov_compare_op (op, mode)
-    register rtx op;
-    enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  enum rtx_code code = GET_CODE (op);
+        sethi  %h44(symbol), %temp1
+        or     %temp1, %m44(symbol), %temp2
+        sllx   %temp2, 12, %temp3
+        or     %temp3, %l44(symbol), %reg  */
+      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);
+       }
 
-  if (GET_RTX_CLASS (code) != '<')
-    return 0;
+      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;
 
-  if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode
-      || GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
-    /* These are the only branches which work with CC_NOOVmode.  */
-    return (code == EQ || code == NE || code == GE || code == LT);
-  return 1;
-}
+    case CM_MEDANY:
+      /* The range spanned by all instructions in the object is less
+        than 2^31 bytes (2GB) and the distance from any instruction
+        to the location of the label _GLOBAL_OFFSET_TABLE_ is less
+        than 2^31 bytes (2GB).
 
-/* Return 1 if this is a 64-bit comparison operator.  This allows the use of
-   MATCH_OPERATOR to recognize all the branch insns.  */
+        The executable can be placed anywhere in the virtual address
+        space.
 
-int
-noov_compare64_op (op, mode)
-    register rtx op;
-    enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  enum rtx_code code = GET_CODE (op);
+        sethi  %hh(symbol), %temp1
+        sethi  %lm(symbol), %temp2
+        or     %temp1, %hm(symbol), %temp3
+        sllx   %temp3, 32, %temp4
+        or     %temp4, %temp2, %temp5
+        or     %temp5, %lo(symbol), %reg  */
+      if (temp)
+       {
+         /* 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))
+           {
+             gcc_assert (ti_temp);
+             temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
+           }
+         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);
+       }
 
-  if (! TARGET_V9)
-    return 0;
+      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;
 
-  if (GET_RTX_CLASS (code) != '<')
-    return 0;
+    case CM_EMBMEDANY:
+      /* Old old old backwards compatibility kruft here.
+        Essentially it is MEDLOW with a fixed 64-bit
+        virtual base added to all data segment addresses.
+        Text-segment stuff is computed like MEDANY, we can't
+        reuse the code above because the relocation knobs
+        look different.
 
-  if (GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
-    /* These are the only branches which work with CCX_NOOVmode.  */
-    return (code == EQ || code == NE || code == GE || code == LT);
-  return (GET_MODE (XEXP (op, 0)) == CCXmode);
-}
+        Data segment:  sethi   %hi(symbol), %temp1
+                       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);
+           }
 
-/* Nonzero if OP is a comparison operator suitable for use in v9
-   conditional move or branch on register contents instructions.  */
+         emit_insn (gen_embmedany_sethi (temp1, op1));
+         emit_insn (gen_embmedany_brsum (temp2, temp1));
+         emit_insn (gen_embmedany_losum (op0, temp2, op1));
+       }
 
-int
-v9_regcmp_op (op, mode)
-     register rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  enum rtx_code code = GET_CODE (op);
+      /* 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
+       {
+         if (temp)
+           {
+             /* 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))
+               {
+                 gcc_assert (ti_temp);
+                 temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
+               }
+             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);
+           }
 
-  if (GET_RTX_CLASS (code) != '<')
-    return 0;
+         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;
 
-  return v9_regcmp_p (code);
+    default:
+      gcc_unreachable ();
+    }
 }
 
-/* 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;
+#if HOST_BITS_PER_WIDE_INT == 32
+void
+sparc_emit_set_const64 (rtx op0 ATTRIBUTE_UNUSED, rtx op1 ATTRIBUTE_UNUSED)
 {
-  return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
+  gcc_unreachable ();
 }
+#else
+/* These avoid problems when cross compiling.  If we do not
+   go through all this hair then the optimizer will see
+   invalid REG_EQUAL notes or in some cases none at all.  */
+static rtx gen_safe_HIGH64 (rtx, HOST_WIDE_INT);
+static rtx gen_safe_SET64 (rtx, HOST_WIDE_INT);
+static rtx gen_safe_OR64 (rtx, HOST_WIDE_INT);
+static rtx gen_safe_XOR64 (rtx, HOST_WIDE_INT);
 
-/* Return nonzero if OP is an operator of mode MODE which can set
-   the condition codes explicitly.  We do not include PLUS and MINUS
-   because these require CC_NOOVmode, which we handle explicitly.  */
-
-int
-cc_arithop (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+/* The optimizer is not to assume anything about exactly
+   which bits are set for a HIGH, they are unspecified.
+   Unfortunately this leads to many missed optimizations
+   during CSE.  We mask out the non-HIGH bits, and matches
+   a plain movdi, to alleviate this problem.  */
+static rtx
+gen_safe_HIGH64 (rtx dest, HOST_WIDE_INT val)
 {
-  if (GET_CODE (op) == AND
-      || GET_CODE (op) == IOR
-      || GET_CODE (op) == XOR)
-    return 1;
-
-  return 0;
+  return gen_rtx_SET (VOIDmode, dest, GEN_INT (val & ~(HOST_WIDE_INT)0x3ff));
 }
 
-/* Return nonzero if OP is an operator of mode MODE which can bitwise
-   complement its second operand and set the condition codes explicitly.  */
-
-int
-cc_arithopn (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+static rtx
+gen_safe_SET64 (rtx dest, HOST_WIDE_INT val)
 {
-  /* XOR is not here because combine canonicalizes (xor (not ...) ...)
-     and (xor ... (not ...)) to (not (xor ...)).  */
-  return (GET_CODE (op) == AND
-         || GET_CODE (op) == IOR);
+  return gen_rtx_SET (VOIDmode, dest, GEN_INT (val));
 }
-\f
-/* Return true if OP is a register, or is a CONST_INT that can fit in a
-   signed 13 bit immediate field.  This is an acceptable SImode operand for
-   most 3 address instructions.  */
 
-int
-arith_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+static rtx
+gen_safe_OR64 (rtx src, HOST_WIDE_INT val)
 {
-  if (register_operand (op, mode))
-    return 1;
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-  return SMALL_INT32 (op);
+  return gen_rtx_IOR (DImode, src, GEN_INT (val));
 }
 
-/* Return true if OP is a constant 4096  */
-
-int
-arith_4096_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+static rtx
+gen_safe_XOR64 (rtx src, HOST_WIDE_INT val)
 {
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-  else
-    return INTVAL (op) == 4096;
+  return gen_rtx_XOR (DImode, src, GEN_INT (val));
 }
 
-/* Return true if OP is suitable as second operand for add/sub */
-
-int
-arith_add_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  return arith_operand (op, mode) || arith_4096_operand (op, mode);
-}
+/* Worker routines for 64-bit constant formation on arch64.
+   One of the key things to be doing in these emissions is
+   to create as many temp REGs as possible.  This makes it
+   possible for half-built constants to be used later when
+   such values are similar to something required later on.
+   Without doing this, the optimizer cannot see such
+   opportunities.  */
 
-/* Return true if OP is a CONST_INT or a CONST_DOUBLE which can fit in the
-   immediate field of OR and XOR instructions.  Used for 64-bit
-   constant formation patterns.  */
-int
-const64_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return ((GET_CODE (op) == CONST_INT
-          && SPARC_SIMM13_P (INTVAL (op)))
-#if HOST_BITS_PER_WIDE_INT != 64
-         || (GET_CODE (op) == CONST_DOUBLE
-             && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))
-             && (CONST_DOUBLE_HIGH (op) ==
-                 ((CONST_DOUBLE_LOW (op) & 0x80000000) != 0 ?
-                  (HOST_WIDE_INT)-1 : 0)))
-#endif
-         );
-}
+static void sparc_emit_set_const64_quick1 (rtx, rtx,
+                                          unsigned HOST_WIDE_INT, int);
 
-/* The same, but only for sethi instructions.  */
-int
-const64_high_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+static void
+sparc_emit_set_const64_quick1 (rtx op0, rtx temp,
+                              unsigned HOST_WIDE_INT low_bits, int is_neg)
 {
-  return ((GET_CODE (op) == CONST_INT
-          && (INTVAL (op) & ~(HOST_WIDE_INT)0x3ff) != 0
-          && SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode))
-          )
-         || (GET_CODE (op) == CONST_DOUBLE
-             && CONST_DOUBLE_HIGH (op) == 0
-             && (CONST_DOUBLE_LOW (op) & ~(HOST_WIDE_INT)0x3ff) != 0
-             && SPARC_SETHI_P (CONST_DOUBLE_LOW (op))));
-}
+  unsigned HOST_WIDE_INT high_bits;
 
-/* Return true if OP is a register, or is a CONST_INT that can fit in a
-   signed 11 bit immediate field.  This is an acceptable SImode operand for
-   the movcc instructions.  */
+  if (is_neg)
+    high_bits = (~low_bits) & 0xffffffff;
+  else
+    high_bits = low_bits;
 
-int
-arith11_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_INT && SPARC_SIMM11_P (INTVAL (op))));
+  emit_insn (gen_safe_HIGH64 (temp, high_bits));
+  if (!is_neg)
+    {
+      emit_insn (gen_rtx_SET (VOIDmode, op0,
+                             gen_safe_OR64 (temp, (high_bits & 0x3ff))));
+    }
+  else
+    {
+      /* If we are XOR'ing with -1, then we should emit a one's complement
+        instead.  This way the combiner will notice logical operations
+        such as ANDN later on and substitute.  */
+      if ((low_bits & 0x3ff) == 0x3ff)
+       {
+         emit_insn (gen_rtx_SET (VOIDmode, op0,
+                                 gen_rtx_NOT (DImode, temp)));
+       }
+      else
+       {
+         emit_insn (gen_rtx_SET (VOIDmode, op0,
+                                 gen_safe_XOR64 (temp,
+                                                 (-(HOST_WIDE_INT)0x400
+                                                  | (low_bits & 0x3ff)))));
+       }
+    }
 }
 
-/* Return true if OP is a register, or is a CONST_INT that can fit in a
-   signed 10 bit immediate field.  This is an acceptable SImode operand for
-   the movrcc instructions.  */
+static void sparc_emit_set_const64_quick2 (rtx, rtx, unsigned HOST_WIDE_INT,
+                                          unsigned HOST_WIDE_INT, int);
 
-int
-arith10_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+static void
+sparc_emit_set_const64_quick2 (rtx op0, rtx temp,
+                              unsigned HOST_WIDE_INT high_bits,
+                              unsigned HOST_WIDE_INT low_immediate,
+                              int shift_count)
 {
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_INT && SPARC_SIMM10_P (INTVAL (op))));
-}
+  rtx temp2 = op0;
 
-/* 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
-   can fit in a 13 bit immediate field.  This is an acceptable DImode operand
-   for most 3 address instructions.  */
+  if ((high_bits & 0xfffffc00) != 0)
+    {
+      emit_insn (gen_safe_HIGH64 (temp, high_bits));
+      if ((high_bits & ~0xfffffc00) != 0)
+       emit_insn (gen_rtx_SET (VOIDmode, op0,
+                               gen_safe_OR64 (temp, (high_bits & 0x3ff))));
+      else
+       temp2 = temp;
+    }
+  else
+    {
+      emit_insn (gen_safe_SET64 (temp, high_bits));
+      temp2 = temp;
+    }
 
-int
-arith_double_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_INT && SMALL_INT (op))
-         || (! TARGET_ARCH64
-             && GET_CODE (op) == CONST_DOUBLE
-             && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
-             && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_HIGH (op) + 0x1000) < 0x2000)
-         || (TARGET_ARCH64
-             && GET_CODE (op) == CONST_DOUBLE
-             && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
-             && ((CONST_DOUBLE_HIGH (op) == -1
-                  && (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000)
-                 || (CONST_DOUBLE_HIGH (op) == 0
-                     && (CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
-}
-
-/* Return true if OP is a constant 4096 for DImode on ARCH64 */
+  /* Now shift it up into place.  */
+  emit_insn (gen_rtx_SET (VOIDmode, op0,
+                         gen_rtx_ASHIFT (DImode, temp2,
+                                         GEN_INT (shift_count))));
 
-int
-arith_double_4096_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return (TARGET_ARCH64 &&
-         ((GET_CODE (op) == CONST_INT && INTVAL (op) == 4096) ||
-          (GET_CODE (op) == CONST_DOUBLE &&
-           CONST_DOUBLE_LOW (op) == 4096 &&
-           CONST_DOUBLE_HIGH (op) == 0)));
+  /* If there is a low immediate part piece, finish up by
+     putting that in as well.  */
+  if (low_immediate != 0)
+    emit_insn (gen_rtx_SET (VOIDmode, op0,
+                           gen_safe_OR64 (op0, low_immediate)));
 }
 
-/* Return true if OP is suitable as second operand for add/sub in DImode */
+static void sparc_emit_set_const64_longway (rtx, rtx, unsigned HOST_WIDE_INT,
+                                           unsigned HOST_WIDE_INT);
 
-int
-arith_double_add_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+/* 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 (rtx op0, rtx temp,
+                               unsigned HOST_WIDE_INT high_bits,
+                               unsigned HOST_WIDE_INT low_bits)
 {
-  return arith_double_operand (op, mode) || arith_double_4096_operand (op, mode);
-}
-
-/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
-   can fit in an 11 bit immediate field.  This is an acceptable DImode
-   operand for the movcc instructions.  */
-/* ??? Replace with arith11_operand?  */
+  rtx sub_temp;
 
-int
-arith11_double_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_DOUBLE
-             && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
-             && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x400) < 0x800
-             && ((CONST_DOUBLE_HIGH (op) == -1
-                  && (CONST_DOUBLE_LOW (op) & 0x400) == 0x400)
-                 || (CONST_DOUBLE_HIGH (op) == 0
-                     && (CONST_DOUBLE_LOW (op) & 0x400) == 0)))
-         || (GET_CODE (op) == CONST_INT
-             && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
-             && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x400) < 0x800));
-}
-
-/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
-   can fit in an 10 bit immediate field.  This is an acceptable DImode
-   operand for the movrcc instructions.  */
-/* ??? Replace with arith10_operand?  */
+  if (reload_in_progress || reload_completed)
+    sub_temp = op0;
+  else
+    sub_temp = gen_reg_rtx (DImode);
 
-int
-arith10_double_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_DOUBLE
-             && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
-             && (unsigned) (CONST_DOUBLE_LOW (op) + 0x200) < 0x400
-             && ((CONST_DOUBLE_HIGH (op) == -1
-                  && (CONST_DOUBLE_LOW (op) & 0x200) == 0x200)
-                 || (CONST_DOUBLE_HIGH (op) == 0
-                     && (CONST_DOUBLE_LOW (op) & 0x200) == 0)))
-         || (GET_CODE (op) == CONST_INT
-             && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
-             && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x200) < 0x400));
-}
-
-/* Return truth value of whether OP is an integer which fits the
-   range constraining immediate operands in most three-address insns,
-   which have a 13 bit immediate field.  */
+  if ((high_bits & 0xfffffc00) != 0)
+    {
+      emit_insn (gen_safe_HIGH64 (temp, high_bits));
+      if ((high_bits & ~0xfffffc00) != 0)
+       emit_insn (gen_rtx_SET (VOIDmode,
+                               sub_temp,
+                               gen_safe_OR64 (temp, (high_bits & 0x3ff))));
+      else
+       sub_temp = temp;
+    }
+  else
+    {
+      emit_insn (gen_safe_SET64 (temp, high_bits));
+      sub_temp = temp;
+    }
 
-int
-small_int (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
-}
+  if (!reload_in_progress && !reload_completed)
+    {
+      rtx temp2 = gen_reg_rtx (DImode);
+      rtx temp3 = gen_reg_rtx (DImode);
+      rtx temp4 = gen_reg_rtx (DImode);
 
-int
-small_int_or_double (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return ((GET_CODE (op) == CONST_INT && SMALL_INT (op))
-         || (GET_CODE (op) == CONST_DOUBLE
-             && CONST_DOUBLE_HIGH (op) == 0
-             && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))));
-}
+      emit_insn (gen_rtx_SET (VOIDmode, temp4,
+                             gen_rtx_ASHIFT (DImode, sub_temp,
+                                             GEN_INT (32))));
 
-/* Recognize operand values for the umul instruction.  That instruction sign
-   extends immediate values just like all other sparc instructions, but
-   interprets the extended result as an unsigned number.  */
+      emit_insn (gen_safe_HIGH64 (temp2, low_bits));
+      if ((low_bits & ~0xfffffc00) != 0)
+       {
+         emit_insn (gen_rtx_SET (VOIDmode, temp3,
+                                 gen_safe_OR64 (temp2, (low_bits & 0x3ff))));
+         emit_insn (gen_rtx_SET (VOIDmode, op0,
+                                 gen_rtx_PLUS (DImode, temp4, temp3)));
+       }
+      else
+       {
+         emit_insn (gen_rtx_SET (VOIDmode, op0,
+                                 gen_rtx_PLUS (DImode, temp4, temp2)));
+       }
+    }
+  else
+    {
+      rtx low1 = GEN_INT ((low_bits >> (32 - 12))          & 0xfff);
+      rtx low2 = GEN_INT ((low_bits >> (32 - 12 - 12))     & 0xfff);
+      rtx low3 = GEN_INT ((low_bits >> (32 - 12 - 12 - 8)) & 0x0ff);
+      int to_shift = 12;
 
-int
-uns_small_int (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-#if HOST_BITS_PER_WIDE_INT > 32
-  /* All allowed constants will fit a CONST_INT.  */
-  return (GET_CODE (op) == CONST_INT
-         && ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000)
-             || (INTVAL (op) >= 0xFFFFF000
-                  && INTVAL (op) <= 0xFFFFFFFF)));
-#else
-  return ((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000)
-         || (GET_CODE (op) == CONST_DOUBLE
-             && CONST_DOUBLE_HIGH (op) == 0
-             && (unsigned) CONST_DOUBLE_LOW (op) - 0xFFFFF000 < 0x1000));
-#endif
+      /* We are in the middle of reload, so this is really
+        painful.  However we do still make an attempt to
+        avoid emitting truly stupid code.  */
+      if (low1 != const0_rtx)
+       {
+         emit_insn (gen_rtx_SET (VOIDmode, op0,
+                                 gen_rtx_ASHIFT (DImode, sub_temp,
+                                                 GEN_INT (to_shift))));
+         emit_insn (gen_rtx_SET (VOIDmode, op0,
+                                 gen_rtx_IOR (DImode, op0, low1)));
+         sub_temp = op0;
+         to_shift = 12;
+       }
+      else
+       {
+         to_shift += 12;
+       }
+      if (low2 != const0_rtx)
+       {
+         emit_insn (gen_rtx_SET (VOIDmode, op0,
+                                 gen_rtx_ASHIFT (DImode, sub_temp,
+                                                 GEN_INT (to_shift))));
+         emit_insn (gen_rtx_SET (VOIDmode, op0,
+                                 gen_rtx_IOR (DImode, op0, low2)));
+         sub_temp = op0;
+         to_shift = 8;
+       }
+      else
+       {
+         to_shift += 8;
+       }
+      emit_insn (gen_rtx_SET (VOIDmode, op0,
+                             gen_rtx_ASHIFT (DImode, sub_temp,
+                                             GEN_INT (to_shift))));
+      if (low3 != const0_rtx)
+       emit_insn (gen_rtx_SET (VOIDmode, op0,
+                               gen_rtx_IOR (DImode, op0, low3)));
+      /* phew...  */
+    }
 }
 
-int
-uns_arith_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  return register_operand (op, mode) || uns_small_int (op, mode);
-}
+/* Analyze a 64-bit constant for certain properties.  */
+static void analyze_64bit_constant (unsigned HOST_WIDE_INT,
+                                   unsigned HOST_WIDE_INT,
+                                   int *, int *, int *);
 
-/* 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;
+static void
+analyze_64bit_constant (unsigned HOST_WIDE_INT high_bits,
+                       unsigned HOST_WIDE_INT low_bits,
+                       int *hbsp, int *lbsp, int *abbasp)
 {
-  return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);
+  int lowest_bit_set, highest_bit_set, all_bits_between_are_set;
+  int i;
+
+  lowest_bit_set = highest_bit_set = -1;
+  i = 0;
+  do
+    {
+      if ((lowest_bit_set == -1)
+         && ((low_bits >> i) & 1))
+       lowest_bit_set = i;
+      if ((highest_bit_set == -1)
+         && ((high_bits >> (32 - i - 1)) & 1))
+       highest_bit_set = (64 - i - 1);
+    }
+  while (++i < 32
+        && ((highest_bit_set == -1)
+            || (lowest_bit_set == -1)));
+  if (i == 32)
+    {
+      i = 0;
+      do
+       {
+         if ((lowest_bit_set == -1)
+             && ((high_bits >> i) & 1))
+           lowest_bit_set = i + 32;
+         if ((highest_bit_set == -1)
+             && ((low_bits >> (32 - i - 1)) & 1))
+           highest_bit_set = 32 - i - 1;
+       }
+      while (++i < 32
+            && ((highest_bit_set == -1)
+                || (lowest_bit_set == -1)));
+    }
+  /* If there are no bits set this should have gone out
+     as one instruction!  */
+  gcc_assert (lowest_bit_set != -1 && highest_bit_set != -1);
+  all_bits_between_are_set = 1;
+  for (i = lowest_bit_set; i <= highest_bit_set; i++)
+    {
+      if (i < 32)
+       {
+         if ((low_bits & (1 << i)) != 0)
+           continue;
+       }
+      else
+       {
+         if ((high_bits & (1 << (i - 32))) != 0)
+           continue;
+       }
+      all_bits_between_are_set = 0;
+      break;
+    }
+  *hbsp = highest_bit_set;
+  *lbsp = lowest_bit_set;
+  *abbasp = all_bits_between_are_set;
 }
 
-/* Return 1 if OP is a valid operand for the source of a move insn.  */
+static int const64_is_2insns (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT);
 
-int
-input_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+static int
+const64_is_2insns (unsigned HOST_WIDE_INT high_bits,
+                  unsigned HOST_WIDE_INT low_bits)
 {
-  /* If both modes are non-void they must be the same.  */
-  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
-    return 0;
-
-  /* Only a tiny bit of handling for CONSTANT_P_RTX is necessary.  */
-  if (GET_CODE (op) == CONST && GET_CODE (XEXP (op, 0)) == CONSTANT_P_RTX)
-    return 1;
+  int highest_bit_set, lowest_bit_set, all_bits_between_are_set;
 
-  /* Allow any one instruction integer constant, and all CONST_INT
-     variants when we are working in DImode and !arch64.  */
-  if (GET_MODE_CLASS (mode) == MODE_INT
-      && ((GET_CODE (op) == CONST_INT
-          && (SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode))
-              || SPARC_SIMM13_P (INTVAL (op))
-              || (mode == DImode
-                  && ! TARGET_ARCH64)))
-         || (TARGET_ARCH64
-             && GET_CODE (op) == CONST_DOUBLE
-             && ((CONST_DOUBLE_HIGH (op) == 0
-                  && SPARC_SETHI_P (CONST_DOUBLE_LOW (op)))
-                 ||
-#if HOST_BITS_PER_WIDE_INT == 64
-                 (CONST_DOUBLE_HIGH (op) == 0
-                  && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op)))
-#else
-                 (SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))
-                  && (((CONST_DOUBLE_LOW (op) & 0x80000000) == 0
-                       && CONST_DOUBLE_HIGH (op) == 0)
-                      || (CONST_DOUBLE_HIGH (op) == -1
-                          && CONST_DOUBLE_LOW (op) & 0x80000000) != 0))
-#endif
-                 ))))
+  if (high_bits == 0
+      || high_bits == 0xffffffff)
     return 1;
 
-  /* If !arch64 and this is a DImode const, allow it so that
-     the splits can be generated.  */
-  if (! TARGET_ARCH64
-      && mode == DImode
-      && GET_CODE (op) == CONST_DOUBLE)
-    return 1;
+  analyze_64bit_constant (high_bits, low_bits,
+                         &highest_bit_set, &lowest_bit_set,
+                         &all_bits_between_are_set);
 
-  if (register_operand (op, mode))
+  if ((highest_bit_set == 63
+       || lowest_bit_set == 0)
+      && all_bits_between_are_set != 0)
     return 1;
 
-  if (GET_MODE_CLASS (mode) == MODE_FLOAT
-      && GET_CODE (op) == CONST_DOUBLE)
+  if ((highest_bit_set - lowest_bit_set) < 21)
     return 1;
 
-  /* If this is a SUBREG, look inside so that we handle
-     paradoxical ones.  */
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-
-  /* Check for valid MEM forms.  */
-  if (GET_CODE (op) == MEM)
-    {
-      rtx inside = XEXP (op, 0);
-
-      if (GET_CODE (inside) == LO_SUM)
-       {
-         /* We can't allow these because all of the splits
-            (eventually as they trickle down into DFmode
-            splits) require offsettable memory references.  */
-         if (! TARGET_V9
-             && GET_MODE (op) == TFmode)
-           return 0;
-
-         return (register_operand (XEXP (inside, 0), Pmode)
-                 && CONSTANT_P (XEXP (inside, 1)));
-       }
-      return memory_address_p (mode, inside);
-    }
-
   return 0;
 }
 
-\f
-/* We know it can't be done in one insn when we get here,
-   the movsi expander guarentees this.  */
-void
-sparc_emit_set_const32 (op0, op1)
-     rtx op0;
-     rtx op1;
-{
-  enum machine_mode mode = GET_MODE (op0);
-  rtx temp;
-
-  if (GET_CODE (op1) == CONST_INT)
-    {
-      HOST_WIDE_INT value = INTVAL (op1);
-
-      if (SPARC_SETHI_P (value & GET_MODE_MASK (mode))
-         || SPARC_SIMM13_P (value))
-       abort ();
-    }
+static unsigned HOST_WIDE_INT create_simple_focus_bits (unsigned HOST_WIDE_INT,
+                                                       unsigned HOST_WIDE_INT,
+                                                       int, int);
 
-  /* Full 2-insn decomposition is needed.  */
-  if (reload_in_progress || reload_completed)
-    temp = op0;
-  else
-    temp = gen_reg_rtx (mode);
+static unsigned HOST_WIDE_INT
+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;
 
-  if (GET_CODE (op1) == CONST_INT)
+  if (lowest_bit_set < 32)
     {
-      /* Emit them as real moves instead of a HIGH/LO_SUM,
-        this way CSE can see everything and reuse intermediate
-        values if it wants.  */
-      if (TARGET_ARCH64
-         && HOST_BITS_PER_WIDE_INT != 64
-         && (INTVAL (op1) & 0x80000000) != 0)
-       emit_insn (gen_rtx_SET
-                  (VOIDmode, temp,
-                   gen_rtx_CONST_DOUBLE (VOIDmode,
-                                         INTVAL (op1) & ~(HOST_WIDE_INT)0x3ff,
-                                         0)));
-      else
-       emit_insn (gen_rtx_SET (VOIDmode, temp,
-                               GEN_INT (INTVAL (op1)
-                                        & ~(HOST_WIDE_INT)0x3ff)));
-
-      emit_insn (gen_rtx_SET (VOIDmode,
-                             op0,
-                             gen_rtx_IOR (mode, temp,
-                                          GEN_INT (INTVAL (op1) & 0x3ff))));
+      lo = (low_bits >> lowest_bit_set) << shift;
+      hi = ((high_bits << (32 - lowest_bit_set)) << shift);
     }
   else
     {
-      /* A symbol, emit in the traditional way.  */
-      emit_insn (gen_rtx_SET (VOIDmode, temp,
-                             gen_rtx_HIGH (mode, op1)));
-      emit_insn (gen_rtx_SET (VOIDmode,
-                             op0, gen_rtx_LO_SUM (mode, temp, op1)));
-
+      lo = 0;
+      hi = ((high_bits >> (lowest_bit_set - 32)) << shift);
     }
+  gcc_assert (! (hi & lo));
+  return (hi | lo);
 }
 
-\f
-/* Sparc-v9 code-model support.  */
+/* Here we are sure to be arch64 and this is an integer constant
+   being loaded into a register.  Emit the most efficient
+   insn sequence possible.  Detection of all the 1-insn cases
+   has been done already.  */
 void
-sparc_emit_set_symbolic_const64 (op0, op1, temp1)
-     rtx op0;
-     rtx op1;
-     rtx temp1;
+sparc_emit_set_const64 (rtx op0, rtx op1)
 {
-  rtx ti_temp1 = 0;
+  unsigned HOST_WIDE_INT high_bits, low_bits;
+  int lowest_bit_set, highest_bit_set;
+  int all_bits_between_are_set;
+  rtx temp = 0;
 
-  if (temp1 && GET_MODE (temp1) == TImode)
-    {
-      ti_temp1 = temp1;
-      temp1 = gen_rtx_REG (DImode, REGNO (temp1));
-    }
+  /* Sanity check that we know what we are working with.  */
+  gcc_assert (TARGET_ARCH64
+             && (GET_CODE (op0) == SUBREG
+                 || (REG_P (op0) && ! SPARC_FP_REG_P (REGNO (op0)))));
 
-  switch (sparc_cmodel)
-    {
-    case CM_MEDLOW:
-      /* The range spanned by all instructions in the object is less
-        than 2^31 bytes (2GB) and the distance from any instruction
-        to the location of the label _GLOBAL_OFFSET_TABLE_ is less
-        than 2^31 bytes (2GB).
+  if (reload_in_progress || reload_completed)
+    temp = op0;
 
-        The executable must be in the low 4TB of the virtual address
-        space.
+  if (GET_CODE (op1) != CONST_INT)
+    {
+      sparc_emit_set_symbolic_const64 (op0, op1, temp);
+      return;
+    }
 
-        sethi  %hi(symbol), %temp
-        or     %temp, %lo(symbol), %reg  */
-      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;
+  if (! temp)
+    temp = gen_reg_rtx (DImode);
 
-    case CM_MEDMID:
-      /* The range spanned by all instructions in the object is less
-        than 2^31 bytes (2GB) and the distance from any instruction
-        to the location of the label _GLOBAL_OFFSET_TABLE_ is less
-        than 2^31 bytes (2GB).
+  high_bits = ((INTVAL (op1) >> 32) & 0xffffffff);
+  low_bits = (INTVAL (op1) & 0xffffffff);
 
-        The executable must be in the low 16TB of the virtual address
-        space.
+  /* low_bits  bits 0  --> 31
+     high_bits bits 32 --> 63  */
 
-        sethi  %h44(symbol), %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));
-      break;
+  analyze_64bit_constant (high_bits, low_bits,
+                         &highest_bit_set, &lowest_bit_set,
+                         &all_bits_between_are_set);
 
-    case CM_MEDANY:
-      /* The range spanned by all instructions in the object is less
-        than 2^31 bytes (2GB) and the distance from any instruction
-        to the location of the label _GLOBAL_OFFSET_TABLE_ is less
-        than 2^31 bytes (2GB).
-
-        The executable can be placed anywhere in the virtual address
-        space.
-
-        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))
-       {
-         if (ti_temp1)
-           temp1 = gen_rtx_REG (DImode, REGNO (temp1) + 1);
-         else
-           abort();
-       }
-
-      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));
-      break;
-
-    case CM_EMBMEDANY:
-      /* Old old old backwards compatibility kruft here.
-        Essentially it is MEDLOW with a fixed 64-bit
-        virtual base added to all data segment addresses.
-        Text-segment stuff is computed like MEDANY, we can't
-        reuse the code above because the relocation knobs
-        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  */
-      if (data_segment_operand (op1, GET_MODE (op1)))
-       {
-         emit_insn (gen_embmedany_sethi (temp1, op1));
-         emit_insn (gen_embmedany_brsum (op0, temp1));
-         emit_insn (gen_embmedany_losum (op0, op0, op1));
-       }
-      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 (ti_temp1)
-               temp1 = gen_rtx_REG (DImode, REGNO (temp1) + 1);
-             else
-               abort();
-           }
-
-         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));
-       }
-      break;
-
-    default:
-      abort();
-    }
-}
-
-/* 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));
-
-#if HOST_BITS_PER_WIDE_INT == 64
-#define GEN_HIGHINT64(__x)             GEN_INT ((__x) & ~(HOST_WIDE_INT)0x3ff)
-#define GEN_INT64(__x)                 GEN_INT (__x)
-#else
-#define GEN_HIGHINT64(__x) \
-       gen_rtx_CONST_DOUBLE (VOIDmode, (__x) & ~(HOST_WIDE_INT)0x3ff, 0)
-#define GEN_INT64(__x) \
-       gen_rtx_CONST_DOUBLE (VOIDmode, (__x) & 0xffffffff, \
-                             ((__x) & 0x80000000 \
-                              ? -1 : 0))
-#endif
-
-/* The optimizer is not to assume anything about exactly
-   which bits are set for a HIGH, they are unspecified.
-   Unfortunately this leads to many missed optimizations
-   during CSE.  We mask out the non-HIGH bits, and matches
-   a plain movdi, to alleviate this problem.  */
-static void
-sparc_emit_set_safe_HIGH64 (dest, val)
-     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;
-{
-  return gen_rtx_SET (VOIDmode, dest, GEN_INT64 (val));
-}
-
-static rtx
-gen_safe_OR64 (src, val)
-     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;
-{
-  return gen_rtx_XOR (DImode, src, GEN_INT64 (val));
-}
-
-/* Worker routines for 64-bit constant formation on arch64.
-   One of the key things to be doing in these emissions is
-   to create as many temp REGs as possible.  This makes it
-   possible for half-built constants to be used later when
-   such values are similar to something required later on.
-   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 (op0, temp, low_bits, is_neg)
-  rtx op0;
-  rtx temp;
-  unsigned HOST_WIDE_INT low_bits;
-  int is_neg;
-{
-  unsigned HOST_WIDE_INT high_bits;
-
-  if (is_neg)
-    high_bits = (~low_bits) & 0xffffffff;
-  else
-    high_bits = low_bits;
-
-  sparc_emit_set_safe_HIGH64 (temp, high_bits);
-  if (!is_neg)
-    {
-      emit_insn (gen_rtx_SET (VOIDmode, op0,
-                             gen_safe_OR64 (temp, (high_bits & 0x3ff))));
-    }
-  else
-    {
-      /* If we are XOR'ing with -1, then we should emit a one's complement
-        instead.  This way the combiner will notice logical operations
-        such as ANDN later on and substitute.  */
-      if ((low_bits & 0x3ff) == 0x3ff)
-       {
-         emit_insn (gen_rtx_SET (VOIDmode, op0,
-                                 gen_rtx_NOT (DImode, temp)));
-       }
-      else
-       {
-         emit_insn (gen_rtx_SET (VOIDmode, op0,
-                                 gen_safe_XOR64 (temp,
-                                                 (-(HOST_WIDE_INT)0x400
-                                                  | (low_bits & 0x3ff)))));
-       }
-    }
-}
-
-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 (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;
-{
-  rtx temp2 = op0;
-
-  if ((high_bits & 0xfffffc00) != 0)
-    {
-      sparc_emit_set_safe_HIGH64 (temp, high_bits);
-      if ((high_bits & ~0xfffffc00) != 0)
-       emit_insn (gen_rtx_SET (VOIDmode, op0,
-                               gen_safe_OR64 (temp, (high_bits & 0x3ff))));
-      else
-       temp2 = temp;
-    }
-  else
-    {
-      emit_insn (gen_safe_SET64 (temp, high_bits));
-      temp2 = temp;
-    }
-
-  /* Now shift it up into place.  */
-  emit_insn (gen_rtx_SET (VOIDmode, op0,
-                         gen_rtx_ASHIFT (DImode, temp2,
-                                         GEN_INT (shift_count))));
-
-  /* If there is a low immediate part piece, finish up by
-     putting that in as well.  */
-  if (low_immediate != 0)
-    emit_insn (gen_rtx_SET (VOIDmode, op0,
-                           gen_safe_OR64 (op0, low_immediate)));
-}
-
-static void sparc_emit_set_const64_longway
-       PARAMS ((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;
-{
-  rtx sub_temp;
-
-  if (reload_in_progress || reload_completed)
-    sub_temp = op0;
-  else
-    sub_temp = gen_reg_rtx (DImode);
-
-  if ((high_bits & 0xfffffc00) != 0)
-    {
-      sparc_emit_set_safe_HIGH64 (temp, high_bits);
-      if ((high_bits & ~0xfffffc00) != 0)
-       emit_insn (gen_rtx_SET (VOIDmode,
-                               sub_temp,
-                               gen_safe_OR64 (temp, (high_bits & 0x3ff))));
-      else
-       sub_temp = temp;
-    }
-  else
-    {
-      emit_insn (gen_safe_SET64 (temp, high_bits));
-      sub_temp = temp;
-    }
-
-  if (!reload_in_progress && !reload_completed)
-    {
-      rtx temp2 = gen_reg_rtx (DImode);
-      rtx temp3 = gen_reg_rtx (DImode);
-      rtx temp4 = gen_reg_rtx (DImode);
-
-      emit_insn (gen_rtx_SET (VOIDmode, temp4,
-                             gen_rtx_ASHIFT (DImode, sub_temp,
-                                             GEN_INT (32))));
-
-      sparc_emit_set_safe_HIGH64 (temp2, low_bits);
-      if ((low_bits & ~0xfffffc00) != 0)
-       {
-         emit_insn (gen_rtx_SET (VOIDmode, temp3,
-                                 gen_safe_OR64 (temp2, (low_bits & 0x3ff))));
-         emit_insn (gen_rtx_SET (VOIDmode, op0,
-                                 gen_rtx_PLUS (DImode, temp4, temp3)));
-       }
-      else
-       {
-         emit_insn (gen_rtx_SET (VOIDmode, op0,
-                                 gen_rtx_PLUS (DImode, temp4, temp2)));
-       }
-    }
-  else
-    {
-      rtx low1 = GEN_INT ((low_bits >> (32 - 12))          & 0xfff);
-      rtx low2 = GEN_INT ((low_bits >> (32 - 12 - 12))     & 0xfff);
-      rtx low3 = GEN_INT ((low_bits >> (32 - 12 - 12 - 8)) & 0x0ff);
-      int to_shift = 12;
-
-      /* We are in the middle of reload, so this is really
-        painful.  However we do still make an attempt to
-        avoid emitting truly stupid code.  */
-      if (low1 != const0_rtx)
-       {
-         emit_insn (gen_rtx_SET (VOIDmode, op0,
-                                 gen_rtx_ASHIFT (DImode, sub_temp,
-                                                 GEN_INT (to_shift))));
-         emit_insn (gen_rtx_SET (VOIDmode, op0,
-                                 gen_rtx_IOR (DImode, op0, low1)));
-         sub_temp = op0;
-         to_shift = 12;
-       }
-      else
-       {
-         to_shift += 12;
-       }
-      if (low2 != const0_rtx)
-       {
-         emit_insn (gen_rtx_SET (VOIDmode, op0,
-                                 gen_rtx_ASHIFT (DImode, sub_temp,
-                                                 GEN_INT (to_shift))));
-         emit_insn (gen_rtx_SET (VOIDmode, op0,
-                                 gen_rtx_IOR (DImode, op0, low2)));
-         sub_temp = op0;
-         to_shift = 8;
-       }
-      else
-       {
-         to_shift += 8;
-       }
-      emit_insn (gen_rtx_SET (VOIDmode, op0,
-                             gen_rtx_ASHIFT (DImode, sub_temp,
-                                             GEN_INT (to_shift))));
-      if (low3 != const0_rtx)
-       emit_insn (gen_rtx_SET (VOIDmode, op0,
-                               gen_rtx_IOR (DImode, op0, low3)));
-      /* phew...  */
-    }
-}
-
-/* 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 (high_bits, low_bits, hbsp, lbsp, abbasp)
-     unsigned HOST_WIDE_INT high_bits, low_bits;
-     int *hbsp, *lbsp, *abbasp;
-{
-  int lowest_bit_set, highest_bit_set, all_bits_between_are_set;
-  int i;
-
-  lowest_bit_set = highest_bit_set = -1;
-  i = 0;
-  do
-    {
-      if ((lowest_bit_set == -1)
-         && ((low_bits >> i) & 1))
-       lowest_bit_set = i;
-      if ((highest_bit_set == -1)
-         && ((high_bits >> (32 - i - 1)) & 1))
-       highest_bit_set = (64 - i - 1);
-    }
-  while (++i < 32
-        && ((highest_bit_set == -1)
-            || (lowest_bit_set == -1)));
-  if (i == 32)
-    {
-      i = 0;
-      do
-       {
-         if ((lowest_bit_set == -1)
-             && ((high_bits >> i) & 1))
-           lowest_bit_set = i + 32;
-         if ((highest_bit_set == -1)
-             && ((low_bits >> (32 - i - 1)) & 1))
-           highest_bit_set = 32 - i - 1;
-       }
-      while (++i < 32
-            && ((highest_bit_set == -1)
-                || (lowest_bit_set == -1)));
-    }
-  /* If there are no bits set this should have gone out
-     as one instruction!  */
-  if (lowest_bit_set == -1
-      || highest_bit_set == -1)
-    abort ();
-  all_bits_between_are_set = 1;
-  for (i = lowest_bit_set; i <= highest_bit_set; i++)
-    {
-      if (i < 32)
-       {
-         if ((low_bits & (1 << i)) != 0)
-           continue;
-       }
-      else
-       {
-         if ((high_bits & (1 << (i - 32))) != 0)
-           continue;
-       }
-      all_bits_between_are_set = 0;
-      break;
-    }
-  *hbsp = highest_bit_set;
-  *lbsp = lowest_bit_set;
-  *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 (high_bits, low_bits)
-     unsigned HOST_WIDE_INT high_bits, low_bits;
-{
-  int highest_bit_set, lowest_bit_set, all_bits_between_are_set;
-
-  if (high_bits == 0
-      || high_bits == 0xffffffff)
-    return 1;
-
-  analyze_64bit_constant (high_bits, low_bits,
-                         &highest_bit_set, &lowest_bit_set,
-                         &all_bits_between_are_set);
-
-  if ((highest_bit_set == 63
-       || lowest_bit_set == 0)
-      && all_bits_between_are_set != 0)
-    return 1;
-
-  if ((highest_bit_set - lowest_bit_set) < 21)
-    return 1;
-
-  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 (high_bits, low_bits, lowest_bit_set, shift)
-     unsigned HOST_WIDE_INT high_bits, low_bits;
-     int lowest_bit_set, shift;
-{
-  HOST_WIDE_INT hi, lo;
-
-  if (lowest_bit_set < 32)
-    {
-      lo = (low_bits >> lowest_bit_set) << shift;
-      hi = ((high_bits << (32 - lowest_bit_set)) << shift);
-    }
-  else
-    {
-      lo = 0;
-      hi = ((high_bits >> (lowest_bit_set - 32)) << shift);
-    }
-  if (hi & lo)
-    abort ();
-  return (hi | lo);
-}
-
-/* Here we are sure to be arch64 and this is an integer constant
-   being loaded into a register.  Emit the most efficient
-   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;
-{
-  unsigned HOST_WIDE_INT high_bits, low_bits;
-  int lowest_bit_set, highest_bit_set;
-  int all_bits_between_are_set;
-  rtx temp;
-
-  /* Sanity check that we know what we are working with.  */
-  if (! TARGET_ARCH64)
-    abort ();
-
-  if (GET_CODE (op0) != SUBREG)
-    {
-      if (GET_CODE (op0) != REG
-         || (REGNO (op0) >= SPARC_FIRST_FP_REG
-             && REGNO (op0) <= SPARC_LAST_V9_FP_REG))
-       abort ();
-    }
-
-  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)
-    {
-      sparc_emit_set_symbolic_const64 (op0, op1, temp);
-      return;
-    }
-
-  if (GET_CODE (op1) == CONST_DOUBLE)
-    {
-#if HOST_BITS_PER_WIDE_INT == 64
-      high_bits = (CONST_DOUBLE_LOW (op1) >> 32) & 0xffffffff;
-      low_bits  = CONST_DOUBLE_LOW (op1) & 0xffffffff;
-#else
-      high_bits = CONST_DOUBLE_HIGH (op1);
-      low_bits = CONST_DOUBLE_LOW (op1);
-#endif
-    }
-  else
-    {
-#if HOST_BITS_PER_WIDE_INT == 64
-      high_bits = ((INTVAL (op1) >> 32) & 0xffffffff);
-      low_bits = (INTVAL (op1) & 0xffffffff);
-#else
-      high_bits = ((INTVAL (op1) < 0) ?
-                  0xffffffff :
-                  0x00000000);
-      low_bits = INTVAL (op1);
-#endif
-    }
-
-  /* low_bits  bits 0  --> 31
-     high_bits bits 32 --> 63  */
-
-  analyze_64bit_constant (high_bits, low_bits,
-                         &highest_bit_set, &lowest_bit_set,
-                         &all_bits_between_are_set);
-
-  /* First try for a 2-insn sequence.  */
+  /* First try for a 2-insn sequence.  */
 
   /* These situations are preferred because the optimizer can
    * do more things with them:
@@ -2023,8 +1764,8 @@ sparc_emit_set_const64 (op0, op1)
       else if (lowest_bit_set == 0)
        shift = -(63 - highest_bit_set);
 
-      if (! SPARC_SIMM13_P (the_const))
-       abort ();
+      gcc_assert (SPARC_SIMM13_P (the_const));
+      gcc_assert (shift != 0);
 
       emit_insn (gen_safe_SET64 (temp, the_const));
       if (shift > 0)
@@ -2039,8 +1780,6 @@ sparc_emit_set_const64 (op0, op1)
                                gen_rtx_LSHIFTRT (DImode,
                                                  temp,
                                                  GEN_INT (-shift))));
-      else
-       abort ();
       return;
     }
 
@@ -2056,10 +1795,10 @@ sparc_emit_set_const64 (op0, op1)
        create_simple_focus_bits (high_bits, low_bits,
                                  lowest_bit_set, 10);
 
-      if (! SPARC_SETHI_P (focus_bits))
-        abort ();
+      gcc_assert (SPARC_SETHI_P (focus_bits));
+      gcc_assert (lowest_bit_set != 10);
 
-      sparc_emit_set_safe_HIGH64 (temp, focus_bits);
+      emit_insn (gen_safe_HIGH64 (temp, focus_bits));
 
       /* If lowest_bit_set == 10 then a sethi alone could have done it.  */
       if (lowest_bit_set < 10)
@@ -2072,8 +1811,6 @@ sparc_emit_set_const64 (op0, op1)
                                op0,
                                gen_rtx_ASHIFT (DImode, temp,
                                                GEN_INT (lowest_bit_set - 10))));
-      else
-       abort ();
       return;
     }
 
@@ -2116,26 +1853,20 @@ sparc_emit_set_const64 (op0, op1)
          || (((~high_bits) & 0xffffffff) == 0xffffffff
              && ((~low_bits) & 0x80000000) != 0))
        {
-         int fast_int = (~low_bits & 0xffffffff);
+         unsigned HOST_WIDE_INT fast_int = (~low_bits & 0xffffffff);
 
          if ((SPARC_SETHI_P (fast_int)
               && (~high_bits & 0xffffffff) == 0)
              || SPARC_SIMM13_P (fast_int))
            emit_insn (gen_safe_SET64 (temp, fast_int));
          else
-           sparc_emit_set_const64 (temp, GEN_INT64 (fast_int));
+           sparc_emit_set_const64 (temp, GEN_INT (fast_int));
        }
       else
        {
          rtx negated_const;
-#if HOST_BITS_PER_WIDE_INT == 64
          negated_const = GEN_INT (((~low_bits) & 0xfffffc00) |
                                   (((HOST_WIDE_INT)((~high_bits) & 0xffffffff))<<32));
-#else
-         negated_const = gen_rtx_CONST_DOUBLE (DImode,
-                                               (~low_bits) & 0xfffffc00,
-                                               (~high_bits) & 0xffffffff);
-#endif
          sparc_emit_set_const64 (temp, negated_const);
        }
 
@@ -2171,9 +1902,7 @@ sparc_emit_set_const64 (op0, op1)
                                  lowest_bit_set, 0);
 
       /* We can't get here in this state.  */
-      if (highest_bit_set < 32
-         || lowest_bit_set >= 32)
-       abort ();
+      gcc_assert (highest_bit_set >= 32 && lowest_bit_set < 32);
 
       /* So what we know is that the set bits straddle the
         middle of the 64-bit word.  */
@@ -2202,6 +1931,7 @@ sparc_emit_set_const64 (op0, op1)
 #endif
   sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits);
 }
+#endif /* HOST_BITS_PER_WIDE_INT == 32 */
 
 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
    return the mode to be used for the comparison.  For floating-point,
@@ -2210,10 +1940,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)
     {
@@ -2238,7 +1965,7 @@ select_cc_mode (op, x, y)
          return CCFPEmode;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
   else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
@@ -2258,17 +1985,23 @@ select_cc_mode (op, x, y)
     }
 }
 
-/* X and Y are two things to compare using CODE.  Emit the compare insn and
-   return the rtx for the cc reg in the proper mode.  */
+/* Emit the compare insn and return the CC reg for a CODE comparison.  */
 
 rtx
-gen_compare_reg (code, x, y)
-     enum rtx_code code;
-     rtx x, y;
+gen_compare_reg (enum rtx_code code)
 {
+  rtx x = sparc_compare_op0;
+  rtx y = sparc_compare_op1;
   enum machine_mode mode = SELECT_CC_MODE (code, x, y);
   rtx cc_reg;
 
+  if (sparc_compare_emitted != NULL_RTX)
+    {
+      cc_reg = sparc_compare_emitted;
+      sparc_compare_emitted = NULL_RTX;
+      return cc_reg;
+    }
+
   /* ??? We don't have movcc patterns so we cannot generate pseudo regs for the
      fcc regs (cse can't tell they're really call clobbered regs and will
      remove a duplicate comparison even if there is an intervening function
@@ -2315,12 +2048,28 @@ gen_compare_reg (code, x, y)
   else
     cc_reg = gen_rtx_REG (mode, SPARC_ICC_REG);
 
-  emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
-                         gen_rtx_COMPARE (mode, x, y)));
+  /* We shouldn't get there for TFmode if !TARGET_HARD_QUAD.  If we do, this
+     will only result in an unrecognizable insn so no point in asserting.  */
+  emit_insn (gen_rtx_SET (VOIDmode, cc_reg, gen_rtx_COMPARE (mode, x, y)));
 
   return cc_reg;
 }
 
+/* Same as above but return the whole compare operator.  */
+
+rtx
+gen_compare_operator (enum rtx_code code)
+{
+  rtx cc_reg;
+
+  if (GET_MODE (sparc_compare_op0) == TFmode && !TARGET_HARD_QUAD)
+    code
+      = sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, code);
+
+  cc_reg = gen_compare_reg (code);
+  return gen_rtx_fmt_ee (code, GET_MODE (cc_reg), cc_reg, const0_rtx);
+}
+
 /* This function is used for v9 only.
    CODE is the code for an Scc's comparison.
    OPERANDS[0] is the target of the Scc insn.
@@ -2345,26 +2094,22 @@ 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;
-
   if (! TARGET_ARCH64
       && (GET_MODE (sparc_compare_op0) == DImode
          || GET_MODE (operands[0]) == DImode))
     return 0;
 
-  op0 = sparc_compare_op0;
-  op1 = sparc_compare_op1;
-
   /* Try to use the movrCC insns.  */
   if (TARGET_ARCH64
-      && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
-      && op1 == const0_rtx
+      && GET_MODE_CLASS (GET_MODE (sparc_compare_op0)) == MODE_INT
+      && sparc_compare_op1 == const0_rtx
       && v9_regcmp_p (compare_code))
     {
+      rtx op0 = sparc_compare_op0;
+      rtx temp;
+
       /* Special case for op0 != 0.  This can be done with one instruction if
         operands[0] == sparc_compare_op0.  */
 
@@ -2407,7 +2152,7 @@ gen_v9_scc (compare_code, operands)
     }
   else
     {
-      operands[1] = gen_compare_reg (compare_code, op0, op1);
+      operands[1] = gen_compare_reg (compare_code);
 
       switch (GET_MODE (operands[1]))
        {
@@ -2417,7 +2162,7 @@ gen_v9_scc (compare_code, operands)
          case CCFPmode :
            break;
          default :
-           abort ();
+           gcc_unreachable ();
        }
       emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx));
       emit_insn (gen_rtx_SET (VOIDmode, operands[0],
@@ -2435,10 +2180,9 @@ 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)
 {
+  gcc_assert (sparc_compare_emitted == NULL_RTX);
   emit_jump_insn (gen_rtx_SET (VOIDmode,
                           pc_rtx,
                           gen_rtx_IF_THEN_ELSE (VOIDmode,
@@ -2453,9 +2197,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);
 
@@ -2469,17 +2211,13 @@ 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;
 
   /* We only expect to be called for conversions, unary, and binary ops.  */
-  if (nargs < 2 || nargs > 3)
-    abort ();
+  gcc_assert (nargs == 2 || nargs == 3);
 
   for (i = 0; i < nargs; ++i)
     {
@@ -2542,8 +2280,7 @@ emit_soft_tfmode_libcall (func_name, nargs, operands)
     {
       rtx ret;
 
-      if (nargs != 2)
-       abort ();
+      gcc_assert (nargs == 2);
 
       ret = emit_library_call_value (func_sym, operands[0], LCT_NORMAL,
                                     GET_MODE (operands[0]), 1,
@@ -2557,9 +2294,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;
 
@@ -2578,35 +2313,25 @@ emit_soft_tfmode_binop (code, operands)
       func = "_Qp_div";
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   emit_soft_tfmode_libcall (func, 3, 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;
 
-  switch (code)
-    {
-    case SQRT:
-      func = "_Qp_sqrt";
-      break;
-    default:
-      abort ();
-    }
+  gcc_assert (code == SQRT);
+  func = "_Qp_sqrt";
 
   emit_soft_tfmode_libcall (func, 2, 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;
 
@@ -2622,7 +2347,7 @@ emit_soft_tfmode_cvt (code, operands)
          func = "_Qp_dtoq";
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       break;
 
@@ -2636,7 +2361,7 @@ emit_soft_tfmode_cvt (code, operands)
          func = "_Qp_qtod";
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       break;
 
@@ -2645,12 +2370,14 @@ emit_soft_tfmode_cvt (code, operands)
        {
        case SImode:
          func = "_Qp_itoq";
+         if (TARGET_ARCH64)
+           operands[1] = gen_rtx_SIGN_EXTEND (DImode, operands[1]);
          break;
        case DImode:
          func = "_Qp_xtoq";
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       break;
 
@@ -2659,12 +2386,14 @@ emit_soft_tfmode_cvt (code, operands)
        {
        case SImode:
          func = "_Qp_uitoq";
+         if (TARGET_ARCH64)
+           operands[1] = gen_rtx_ZERO_EXTEND (DImode, operands[1]);
          break;
        case DImode:
          func = "_Qp_uxtoq";
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       break;
 
@@ -2678,7 +2407,7 @@ emit_soft_tfmode_cvt (code, operands)
          func = "_Qp_qtox";
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       break;
 
@@ -2692,12 +2421,12 @@ emit_soft_tfmode_cvt (code, operands)
          func = "_Qp_qtoux";
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   emit_soft_tfmode_libcall (func, 2, operands);
@@ -2707,13 +2436,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]);
@@ -2738,9 +2465,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);
@@ -2749,9 +2474,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);
@@ -2760,9 +2483,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);
@@ -2770,20 +2491,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;
 
@@ -2798,71 +2510,56 @@ 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;
+  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;
+  /* 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;
 
-  /* If the function uses __builtin_eh_return, the eh_return machinery
-     occupies the delay slot.  */
-  if (current_function_calls_eh_return)
-    return 0;
+  pat = PATTERN (trial);
 
-  /* 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)
+  /* We must reject tgd_add{32|64}, i.e.
+       (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSGD)))
+     and tldm_add{32|64}, i.e.
+       (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSLDM)))
+     for Sun as/ld.  */
+  if (GET_CODE (pat) == SET
+      && GET_CODE (SET_SRC (pat)) == PLUS)
     {
-      if (leaf_return_peephole_ok ())
-       return ((get_attr_in_uncond_branch_delay (trial)
-                == IN_BRANCH_DELAY_TRUE));
-      return 0;
-    }
+      rtx unspec = XEXP (SET_SRC (pat), 1);
 
-  pat = PATTERN (trial);
+      if (GET_CODE (unspec) == UNSPEC
+         && (XINT (unspec, 1) == UNSPEC_TLSGD
+             || XINT (unspec, 1) == UNSPEC_TLSLDM))
+       return 0;
+    }
 
-  /* 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;
+  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 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)))
     {
@@ -2872,41 +2569,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;
 
-  /* If we have return instruction, anything that does not use
+  /* 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 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)
@@ -2916,24 +2611,72 @@ 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.  */
-  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;
+  /* The 'restore src,src,dest' pattern.  */
+  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;
+}
+
+/* Return nonzero if TRIAL can go into the function return's
+   delay slot.  */
+
+int
+eligible_for_return_delay (rtx trial)
+{
+  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 (crtl->calls_eh_return)
+    return 0;
+
+  /* In the case of a true leaf function, anything can go into the slot.  */
+  if (sparc_leaf_function_p)
+    return get_attr_in_uncond_branch_delay (trial)
+          == IN_UNCOND_BRANCH_DELAY_TRUE;
 
-  return 0;
+  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
+/* 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;
+  rtx pat;
 
   if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
     return 0;
@@ -2943,11 +2686,11 @@ eligible_for_sibcall_delay (trial)
 
   pat = PATTERN (trial);
 
-  if (current_function_uses_only_leaf_regs)
+  if (sparc_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 */
@@ -2960,7 +2703,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;
 
@@ -2969,220 +2712,564 @@ eligible_for_sibcall_delay (trial)
   if (reg_mentioned_p (gen_rtx_REG (Pmode, 15), pat))
     return 0;
 
-  src = SET_SRC (pat);
+  return eligible_for_restore_insn (trial, false);
+}
 
-  if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
-      && arith_operand (src, GET_MODE (src)))
+int
+short_branch (int uid1, int 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 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 (rtx reg, rtx insn)
+{
+  enum rtx_code code, prev_code = UNKNOWN;
+
+  while ((insn = NEXT_INSN (insn)))
     {
-      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);
+      if (prev_code == CALL_INSN && call_used_regs[REGNO (reg)])
+       return 1;
+
+      code = GET_CODE (insn);
+      if (GET_CODE (insn) == CODE_LABEL)
+       return 1;
+
+      if (INSN_P (insn))
+       {
+         rtx set = single_set (insn);
+         int in_src = set && reg_overlap_mentioned_p (reg, SET_SRC (set));
+         if (set && in_src)
+           return 0;
+         if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+           return 1;
+         if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
+           return 0;
+       }
+      prev_code = code;
     }
+  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).  */
 
-  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);
+static bool
+sparc_cannot_force_const_mem (rtx x)
+{
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case CONST_VECTOR:
+      /* Accept all non-symbolic constants.  */
+      return false;
 
-  else if (! TARGET_FPU && restore_operand (SET_DEST (pat), SFmode)
-          && register_operand (src, SFmode))
-    return 1;
+    case LABEL_REF:
+      /* Labels are OK iff we are non-PIC.  */
+      return flag_pic != 0;
 
-  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)))
-    return 1;
+    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;
 
-  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;
+    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:
+      gcc_unreachable ();
+    }
+}
+\f
+/* PIC support.  */
+static GTY(()) char pic_helper_symbol_name[256];
+static GTY(()) rtx pic_helper_symbol;
+static GTY(()) bool pic_helper_emitted_p = false;
+static GTY(()) rtx global_offset_table;
 
-  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;
+/* Ensure that we are not using patterns that are not OK with PIC.  */
 
-  else if (GET_CODE (src) == ASHIFT
-          && (register_operand (XEXP (src, 0), SImode)
-              || register_operand (XEXP (src, 0), DImode))
-          && XEXP (src, 1) == const1_rtx)
+int
+check_pic (int i)
+{
+  switch (flag_pic)
+    {
+    case 1:
+      gcc_assert (GET_CODE (recog_data.operand[i]) != SYMBOL_REF
+                 && (GET_CODE (recog_data.operand[i]) != CONST
+                 || (GET_CODE (XEXP (recog_data.operand[i], 0)) == MINUS
+                     && (XEXP (XEXP (recog_data.operand[i], 0), 0)
+                         == global_offset_table)
+                     && (GET_CODE (XEXP (XEXP (recog_data.operand[i], 0), 1))
+                         == CONST))));
+    case 2:
+    default:
+      return 1;
+    }
+}
+
+/* Return true if X is an address which needs a temporary register when 
+   reloaded while generating PIC code.  */
+
+int
+pic_address_needs_scratch (rtx x)
+{
+  /* An address which is a symbolic plus a non SMALL_INT needs a temp reg.  */
+  if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
+      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+      && ! SMALL_INT (XEXP (XEXP (x, 0), 1)))
     return 1;
 
   return 0;
 }
 
-static int
-check_return_regs (x)
-     rtx x;
+/* Determine if a given RTX is a valid constant.  We already know this
+   satisfies CONSTANT_P.  */
+
+bool
+legitimate_constant_p (rtx x)
 {
   switch (GET_CODE (x))
     {
-    case REG:
-      return IN_OR_GLOBAL_P (x);
+    case CONST:
+    case SYMBOL_REF:
+      if (sparc_tls_referenced_p (x))
+       return false;
+      break;
 
-    case CONST_INT:
     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
+         && SCALAR_FLOAT_MODE_P (GET_MODE (x))
+         && const_zero_operand (x, GET_MODE (x)))
+       return true;
+
+      return false;
+
+    case CONST_VECTOR:
+      /* Vector constants are generally not ok.
+        The only exception is 0 in VIS.  */
+      if (TARGET_VIS
+         && const_zero_operand (x, GET_MODE (x)))
+       return true;
+
+      return false;
+
+    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:
-    case LABEL_REF:
-    return 1;
+      return !flag_pic && legitimate_constant_p (x);
 
-    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;
+      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 (sparc_tls_referenced_p (x))
+    return false;
+  return true;
 }
 
-/* Return 1 if TRIAL references only in and global registers.  */
+/* Return nonzero if ADDR is a valid memory address.
+   STRICT specifies whether strict register checking applies.  */
+   
 int
-eligible_for_return_delay (trial)
-     rtx trial;
-{
-  if (GET_CODE (PATTERN (trial)) != SET)
+legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
+{
+  rtx rs1 = NULL, rs2 = NULL, imm1 = NULL;
+
+  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
+          && !(GET_CODE (rs2) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rs2))
+          && (! symbolic_operand (rs2, VOIDmode) || mode == Pmode)
+          && (GET_CODE (rs2) != CONST_INT || SMALL_INT (rs2)))
+         || ((REG_P (rs1)
+              || 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 quad move insns
+            and we consequently need to split.  We do this because REG+REG
+            is not an offsettable address.  If we get the situation in reload
+            where source and destination of a movtf pattern are both MEMs with
+            REG+REG address, then only one of them gets converted to an
+            offsettable address.  */
+         if (mode == TFmode
+             && ! (TARGET_FPU && TARGET_ARCH64 && 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))
+       {
+         rs2 = NULL;
+         imm1 = XEXP (rs1, 1);
+         rs1 = XEXP (rs1, 0);
+         if (!CONSTANT_P (imm1)
+             || (GET_CODE (rs1) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rs1)))
+           return 0;
+       }
+    }
+  else if (GET_CODE (addr) == LO_SUM)
+    {
+      rs1 = XEXP (addr, 0);
+      imm1 = XEXP (addr, 1);
+
+      if (!CONSTANT_P (imm1)
+         || (GET_CODE (rs1) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rs1)))
+       return 0;
+
+      /* We can't allow TFmode in 32-bit mode, because an offset greater
+        than the alignment (8) may cause the LO_SUM to overflow.  */
+      if (mode == TFmode && TARGET_ARCH32)
+       return 0;
+    }
+  else if (GET_CODE (addr) == CONST_INT && SMALL_INT (addr))
+    return 1;
+  else
+    return 0;
+
+  if (GET_CODE (rs1) == SUBREG)
+    rs1 = SUBREG_REG (rs1);
+  if (!REG_P (rs1))
     return 0;
 
-  return check_return_regs (PATTERN (trial));
+  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;
 }
 
-int
-short_branch (uid1, uid2)
-     int uid1, uid2;
+static rtx
+sparc_tls_got (void)
 {
-  int delta = INSN_ADDRESSES (uid1) - INSN_ADDRESSES (uid2);
+  rtx temp;
+  if (flag_pic)
+    {
+      crtl->uses_pic_offset_table = 1;
+      return pic_offset_table_rtx;
+    }
 
-  /* Leave a few words of "slop".  */
-  if (delta >= -1023 && delta <= 1022)
-    return 1;
+  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;
+}
 
-  return 0;
+/* Return true if X contains a thread-local symbol.  */
+
+static bool
+sparc_tls_referenced_p (rtx x)
+{
+  if (!TARGET_HAVE_TLS)
+    return false;
+
+  if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
+    x = XEXP (XEXP (x, 0), 0);
+
+  if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
+    return true;
+
+  /* That's all we handle in legitimize_tls_address for now.  */
+  return false;
 }
 
-/* Return non-zero 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;
+/* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
+   this (thread-local) address.  */
+
+static rtx
+legitimize_tls_address (rtx addr)
 {
-  enum rtx_code code, prev_code = UNKNOWN;
+  rtx temp1, temp2, temp3, ret, o0, got, insn;
 
-  while ((insn = NEXT_INSN (insn)))
-    {
-      if (prev_code == CALL_INSN && call_used_regs[REGNO (reg)])
-       return 1;
+  gcc_assert (can_create_pseudo_p ());
+
+  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;
 
-      code = GET_CODE (insn);
-      if (GET_CODE (insn) == CODE_LABEL)
-       return 1;
+      default:
+       gcc_unreachable ();
+      }
 
-      if (GET_RTX_CLASS (code) == 'i')
-       {
-         rtx set = single_set (insn);
-         int in_src = set && reg_overlap_mentioned_p (reg, SET_SRC (set));
-         if (set && in_src)
-           return 0;
-         if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
-           return 1;
-         if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
-           return 0;
-       }
-      prev_code = code;
-    }
-  return 1;
-}
-\f
-/* The table we use to reference PIC data.  */
-static rtx global_offset_table;
+  else if (GET_CODE (addr) == CONST)
+    {
+      rtx base, offset;
 
-/* The function we use to get at it.  */
-static rtx get_pc_symbol;
-static char get_pc_symbol_name[256];
+      gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS);
 
-/* Ensure that we are not using patterns that are not OK with PIC.  */
+      base = legitimize_tls_address (XEXP (XEXP (addr, 0), 0));
+      offset = XEXP (XEXP (addr, 0), 1);
 
-int
-check_pic (i)
-     int i;
-{
-  switch (flag_pic)
-    {
-    case 1:
-      if (GET_CODE (recog_data.operand[i]) == SYMBOL_REF
-         || (GET_CODE (recog_data.operand[i]) == CONST
-             && ! (GET_CODE (XEXP (recog_data.operand[i], 0)) == MINUS
-                   && (XEXP (XEXP (recog_data.operand[i], 0), 0)
-                       == global_offset_table)
-                   && (GET_CODE (XEXP (XEXP (recog_data.operand[i], 0), 1))
-                       == CONST))))
-       abort ();
-    case 2:
-    default:
-      return 1;
+      base = force_operand (base, NULL_RTX);
+      if (!(GET_CODE (offset) == CONST_INT && SMALL_INT (offset)))
+       offset = force_reg (Pmode, offset);
+      ret = gen_rtx_PLUS (Pmode, base, offset);
     }
-}
-
-/* Return true if X is an address which needs a temporary register when 
-   reloaded while generating PIC code.  */
 
-int
-pic_address_needs_scratch (x)
-     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
-      && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
-      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-      && ! SMALL_INT (XEXP (XEXP (x, 0), 1)))
-    return 1;
+  else
+    gcc_unreachable ();  /* for now ... */
 
-  return 0;
+  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 non zero, otherwise we allocate register(s) as
+   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;
+static rtx
+legitimize_pic_address (rtx orig, rtx reg)
 {
-  if (GET_CODE (orig) == SYMBOL_REF)
+  if (GET_CODE (orig) == SYMBOL_REF
+      /* See the comment in sparc_expand_move.  */
+      || (TARGET_VXWORKS_RTP && GET_CODE (orig) == LABEL_REF))
     {
       rtx pic_ref, address;
       rtx insn;
 
       if (reg == 0)
        {
-         if (reload_in_progress || reload_completed)
-           abort ();
-         else
-           reg = gen_reg_rtx (Pmode);
+         gcc_assert (! reload_in_progress && ! reload_completed);
+         reg = gen_reg_rtx (Pmode);
        }
 
       if (flag_pic == 2)
@@ -3197,31 +3284,29 @@ legitimize_pic_address (orig, mode, reg)
             won't get confused into thinking that these two instructions
             are loading in the true address of the symbol.  If in the
             future a PIC rtx exists, that should be used instead.  */
-         if (Pmode == SImode)
+         if (TARGET_ARCH64)
            {
-             emit_insn (gen_movsi_high_pic (temp_reg, orig));
-             emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig));
+             emit_insn (gen_movdi_high_pic (temp_reg, orig));
+             emit_insn (gen_movdi_lo_sum_pic (temp_reg, temp_reg, orig));
            }
          else
            {
-             emit_insn (gen_movdi_high_pic (temp_reg, orig));
-             emit_insn (gen_movdi_lo_sum_pic (temp_reg, temp_reg, orig));
+             emit_insn (gen_movsi_high_pic (temp_reg, orig));
+             emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig));
            }
          address = temp_reg;
        }
       else
        address = orig;
 
-      pic_ref = gen_rtx_MEM (Pmode,
-                            gen_rtx_PLUS (Pmode,
-                                          pic_offset_table_rtx, address));
-      current_function_uses_pic_offset_table = 1;
-      RTX_UNCHANGING_P (pic_ref) = 1;
+      pic_ref = gen_const_mem (Pmode,
+                              gen_rtx_PLUS (Pmode,
+                                            pic_offset_table_rtx, address));
+      crtl->uses_pic_offset_table = 1;
       insn = emit_move_insn (reg, pic_ref);
       /* Put a REG_EQUAL note on this insn, so that it can be optimized
         by loop.  */
-      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
-                                 REG_NOTES (insn));
+      set_unique_reg_note (insn, REG_EQUAL, orig);
       return reg;
     }
   else if (GET_CODE (orig) == CONST)
@@ -3234,20 +3319,14 @@ legitimize_pic_address (orig, mode, reg)
 
       if (reg == 0)
        {
-         if (reload_in_progress || reload_completed)
-           abort ();
-         else
-           reg = gen_reg_rtx (Pmode);
+         gcc_assert (! reload_in_progress && ! reload_completed);
+         reg = gen_reg_rtx (Pmode);
        }
 
-      if (GET_CODE (XEXP (orig, 0)) == PLUS)
-       {
-         base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
-         offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
-                                        base == reg ? 0 : reg);
-       }
-      else
-       abort ();
+      gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
+      base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), reg);
+      offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
+                                      base == reg ? NULL_RTX : reg);
 
       if (GET_CODE (offset) == CONST_INT)
        {
@@ -3257,7 +3336,7 @@ legitimize_pic_address (orig, mode, reg)
            offset = force_reg (Pmode, offset);
          else
            /* If we reach here, then something is seriously wrong.  */
-           abort ();
+           gcc_unreachable ();
        }
       return gen_rtx_PLUS (Pmode, base, offset);
     }
@@ -3265,62 +3344,153 @@ legitimize_pic_address (orig, mode, reg)
     /* ??? Why do we do this?  */
     /* Now movsi_pic_label_ref uses it, but we ought to be checking that
        the register is live instead, in case it is eliminated.  */
-    current_function_uses_pic_offset_table = 1;
+    crtl->uses_pic_offset_table = 1;
 
   return orig;
 }
 
-/* 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 (sparc_tls_referenced_p (x))
+    x = legitimize_tls_address (x);
+  else if (flag_pic)
+    x = legitimize_pic_address (x, NULL_RTX);
+  else if (GET_CODE (x) == PLUS && CONSTANT_ADDRESS_P (XEXP (x, 1)))
+    x = gen_rtx_PLUS (Pmode, XEXP (x, 0),
+                     copy_to_mode_reg (Pmode, XEXP (x, 1)));
+  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 helper function.  */
+
+static void
+emit_pic_helper (void)
 {
-  /* Labels to get the PC in the prologue of this function.  */
-  int orig_flag_pic = flag_pic;
+  const char *pic_name = reg_names[REGNO (pic_offset_table_rtx)];
+  int align;
 
-  if (! flag_pic)
-    abort ();
+  switch_to_section (text_section);
 
-  /* If we haven't emitted the special get_pc helper function, do so now.  */
-  if (get_pc_symbol_name[0] == 0)
-    {
-      int align;
+  align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+  if (align > 0)
+    ASM_OUTPUT_ALIGN (asm_out_file, align);
+  ASM_OUTPUT_LABEL (asm_out_file, pic_helper_symbol_name);
+  if (flag_delayed_branch)
+    fprintf (asm_out_file, "\tjmp\t%%o7+8\n\t add\t%%o7, %s, %s\n",
+           pic_name, pic_name);
+  else
+    fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp\t%%o7+8\n\t nop\n",
+           pic_name, pic_name);
 
-      ASM_GENERATE_INTERNAL_LABEL (get_pc_symbol_name, "LGETPC", 0);
-      text_section ();
+  pic_helper_emitted_p = true;
+}
+
+/* Emit code to load the PIC register.  */
+
+static void
+load_pic_register (bool delay_pic_helper)
+{
+  int orig_flag_pic = flag_pic;
 
-      align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
-      if (align > 0)
-       ASM_OUTPUT_ALIGN (asm_out_file, align);
-      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LGETPC", 0);
-      fputs ("\tretl\n\tadd\t%o7, %l7, %l7\n", asm_out_file);
+  if (TARGET_VXWORKS_RTP)
+    {
+      emit_insn (gen_vxworks_load_got ());
+      emit_use (pic_offset_table_rtx);
+      return;
     }
 
-  /* 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;
+  /* If we haven't initialized the special PIC symbols, do so now.  */
+  if (!pic_helper_symbol_name[0])
+    {
+      ASM_GENERATE_INTERNAL_LABEL (pic_helper_symbol_name, "LADDPC", 0);
+      pic_helper_symbol = gen_rtx_SYMBOL_REF (Pmode, pic_helper_symbol_name);
+      global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+    }
 
-  emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
-                        get_pc_symbol));
+  /* If we haven't emitted the special PIC helper function, do so now unless
+     we are requested to delay it.  */
+  if (!delay_pic_helper && !pic_helper_emitted_p)
+    emit_pic_helper ();
 
+  flag_pic = 0;
+  if (TARGET_ARCH64)
+    emit_insn (gen_load_pcrel_symdi (pic_offset_table_rtx, global_offset_table,
+                                    pic_helper_symbol));
+  else
+    emit_insn (gen_load_pcrel_symsi (pic_offset_table_rtx, global_offset_table,
+                                    pic_helper_symbol));
   flag_pic = orig_flag_pic;
 
   /* Need to emit this whether or not we obey regdecls,
      since setjmp/longjmp can cause life info to screw up.
      ??? In the case where we don't obey regdecls, this is not sufficient
      since we may not fall out the bottom.  */
-  emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+  emit_use (pic_offset_table_rtx);
+}
+
+/* Emit a call instruction with the pattern given by PAT.  ADDR is the
+   address of the call target.  */
+
+void
+sparc_emit_call_insn (rtx pat, rtx addr)
+{
+  rtx insn;
+
+  insn = emit_call_insn (pat);
+
+  /* The PIC register is live on entry to VxWorks PIC PLT entries.  */
+  if (TARGET_VXWORKS_RTP
+      && flag_pic
+      && GET_CODE (addr) == SYMBOL_REF
+      && (SYMBOL_REF_DECL (addr)
+         ? !targetm.binds_local_p (SYMBOL_REF_DECL (addr))
+         : !SYMBOL_REF_LOCAL_P (addr)))
+    {
+      use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
+      crtl->uses_pic_offset_table = 1;
+    }
 }
 \f
 /* Return 1 if RTX is a MEM which is known to be aligned to at
    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;
 
@@ -3328,6 +3498,13 @@ mem_min_alignment (mem, desired)
   if (GET_CODE (mem) != MEM)
     return 0;
 
+  /* Obviously...  */
+  if (!TARGET_UNALIGNED_DOUBLES
+      && MEM_ALIGN (mem) / BITS_PER_UNIT >= (unsigned)desired)
+    return 1;
+
+  /* ??? The rest of the function predates MEM_ALIGN so
+     there is probably a bit of redundancy.  */
   addr = XEXP (mem, 0);
   base = offset = NULL_RTX;
   if (GET_CODE (addr) == PLUS)
@@ -3391,12 +3568,12 @@ mem_min_alignment (mem, desired)
 
 \f
 /* Vectors to keep interesting information about registers where it can easily
-   be got.  We use to use the actual mode value as the bit number, but there
+   be got.  We used to use the actual mode value as the bit number, but there
    are more than 32 modes now.  Instead we use two tables: one indexed by
    hard register number, and one indexed by mode.  */
 
 /* The purpose of sparc_mode_class is to shrink the range of modes so that
-   they all fit (as bit numbers) in a 32 bit word (again).  Each real mode is
+   they all fit (as bit numbers) in a 32-bit word (again).  Each real mode is
    mapped into one sparc_mode_class mode.  */
 
 enum sparc_mode_class {
@@ -3513,7 +3690,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;
 
@@ -3535,6 +3712,12 @@ sparc_init_modes ()
          else 
            sparc_mode_class[i] = 0;
          break;
+       case MODE_VECTOR_INT:
+         if (GET_MODE_SIZE (i) <= 4)
+           sparc_mode_class[i] = 1 << (int)SF_MODE;
+         else if (GET_MODE_SIZE (i) == 8)
+           sparc_mode_class[i] = 1 << (int)DF_MODE;
+         break;
        case MODE_FLOAT:
        case MODE_COMPLEX_FLOAT:
          if (GET_MODE_SIZE (i) <= 4)
@@ -3549,16 +3732,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;
        }
     }
@@ -3586,167 +3766,44 @@ 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.  */
-
-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;
-{
-  int i;
-
-  if (TARGET_ARCH64 && high <= 32)
-    {
-      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().  */
+   during the reload pass and also by sparc_expand_prologue.  */
 
-int
-compute_frame_size (size, leaf_function)
-     int size;
-     int leaf_function;
+HOST_WIDE_INT
+sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function_p)
 {
-  int n_regs = 0, i;
-  int outgoing_args_size = (current_function_outgoing_args_size
+  int outgoing_args_size = (crtl->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.  */
+  int n_regs = 0;  /* N_REGS is the number of 4-byte regs saved thus far.  */
+  int i;
 
   if (TARGET_ARCH64)
     {
       for (i = 0; i < 8; i++)
-       if (regs_ever_live[i] && ! call_used_regs[i])
+       if (df_regs_ever_live_p (i) && ! call_used_regs[i])
          n_regs += 2;
     }
   else
     {
       for (i = 0; i < 8; i += 2)
-       if ((regs_ever_live[i] && ! call_used_regs[i])
-           || (regs_ever_live[i+1] && ! call_used_regs[i+1]))
+       if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
+           || (df_regs_ever_live_p (i+1) && ! call_used_regs[i+1]))
          n_regs += 2;
     }
 
   for (i = 32; i < (TARGET_V9 ? 96 : 64); i += 2)
-    if ((regs_ever_live[i] && ! call_used_regs[i])
-       || (regs_ever_live[i+1] && ! call_used_regs[i+1]))
+    if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
+       || (df_regs_ever_live_p (i+1) && ! call_used_regs[i+1]))
       n_regs += 2;
 
-  /* Set up values for use in `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
+      && crtl->outgoing_args_size == 0)
+    actual_fsize = apparent_fsize = 0;
   else
     {
       /* We subtract STARTING_FRAME_OFFSET, remember it's negative.  */
@@ -3757,49 +3814,17 @@ compute_frame_size (size, leaf_function)
 
   /* Make sure nothing can clobber our register windows.
      If a SAVE must be done, or there is a stack-local variable,
-     the register window area must be allocated.
-     ??? For v8 we apparently need an additional 8 bytes of reserved space.  */
-  if (leaf_function == 0 || size > 0)
-    actual_fsize += (16 * UNITS_PER_WORD) + (TARGET_ARCH64 ? 0 : 8);
+     the register window area must be allocated.  */
+  if (! leaf_function_p || size > 0)
+    actual_fsize += FIRST_PARM_OFFSET (current_function_decl);
 
   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;
@@ -3811,492 +3836,535 @@ sparc_output_scratch_registers (file)
      .register being printed for them already.  */
   for (i = 2; i < 8; i++)
     {
-      if (regs_ever_live [i]
+      if (df_regs_ever_live_p (i)
          && ! sparc_hard_reg_printed [i])
        {
          sparc_hard_reg_printed [i] = 1;
-         fprintf (file, "\t.register\t%%g%d, #scratch\n", i);
+         /* %g7 is used as TLS base register, use #ignore
+            for it instead of #scratch.  */
+         fprintf (file, "\t.register\t%%g%d, #%s\n", i,
+                  i == 7 ? "ignore" : "scratch");
        }
       if (i == 3) i = 5;
     }
 #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 (df_regs_ever_live_p (i) && ! call_used_regs[i])
+           {
+             mem = gen_rtx_MEM (DImode, plus_constant (base, offset));
+             set_mem_alias_set (mem, sparc_sr_alias_set);
+             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 = df_regs_ever_live_p (i) && ! call_used_regs[i];
+         bool reg1 = df_regs_ever_live_p (i+1) && ! call_used_regs[i+1];
+         enum machine_mode mode;
+         int regno;
+
+         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;
+       }
+    }
 
-/* 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.
+  return offset;
+}
 
-   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 save call-saved registers.  */
 
 static void
-sparc_output_function_prologue (file, size)
-     FILE *file;
-     HOST_WIDE_INT size;
+emit_save_or_restore_regs (int action)
+{
+  HOST_WIDE_INT offset;
+  rtx base;
+
+  offset = frame_base_offset - apparent_fsize;
+
+  if (offset < -4096 || offset + num_gfregs * 4 > 4095)
+    {
+      /* ??? 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;
+
+  offset = save_or_restore_regs (0, 8, base, offset, action);
+  save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, action);
+}
+
+/* Generate a save_register_window insn.  */
+
+static rtx
+gen_save_register_window (rtx increment)
 {
-  if (TARGET_FLAT)
-    sparc_flat_function_prologue (file, size);
+  if (TARGET_ARCH64)
+    return gen_save_register_windowdi (increment);
   else
-    sparc_nonflat_function_prologue (file, size,
-                                    current_function_uses_only_leaf_regs);
+    return gen_save_register_windowsi (increment);
 }
 
-/* Output code for the function prologue.  */
+/* Generate 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;
+static rtx
+gen_stack_pointer_inc (rtx increment)
 {
-  sparc_output_scratch_registers (file);
+  return gen_rtx_SET (VOIDmode,
+                     stack_pointer_rtx,
+                     gen_rtx_PLUS (Pmode,
+                                   stack_pointer_rtx,
+                                   increment));
+}
+
+/* Generate a decrement for the stack pointer.  */
+
+static rtx
+gen_stack_pointer_dec (rtx decrement)
+{
+  return gen_rtx_SET (VOIDmode,
+                     stack_pointer_rtx,
+                     gen_rtx_MINUS (Pmode,
+                                    stack_pointer_rtx,
+                                    decrement));
+}
+
+/* Expand the function prologue.  The prologue is responsible for reserving
+   storage for the frame, saving the call-saved registers and loading the
+   PIC register if needed.  */
+
+void
+sparc_expand_prologue (void)
+{
+  rtx insn;
+  int i;
+
+  /* Compute a snapshot of current_function_uses_only_leaf_regs.  Relying
+     on the final value of the flag means deferring the prologue/epilogue
+     expansion until just before the second scheduling pass, which is too
+     late to emit multiple epilogues or return insns.
+
+     Of course we are making the assumption that the value of the flag
+     will not change between now and its final value.  Of the three parts
+     of the formula, only the last one can reasonably vary.  Let's take a
+     closer look, after assuming that the first two ones are set to true
+     (otherwise the last value is effectively silenced).
+
+     If only_leaf_regs_used returns false, the global predicate will also
+     be false so the actual frame size calculated below will be positive.
+     As a consequence, the save_register_window insn will be emitted in
+     the instruction stream; now this insn explicitly references %fp
+     which is not a leaf register so only_leaf_regs_used will always
+     return false subsequently.
+
+     If only_leaf_regs_used returns true, we hope that the subsequent
+     optimization passes won't cause non-leaf registers to pop up.  For
+     example, the regrename pass has special provisions to not rename to
+     non-leaf registers in a leaf function.  */
+  sparc_leaf_function_p
+    = optimize > 0 && leaf_function_p () && only_leaf_regs_used ();
 
   /* Need to use actual_fsize, since we are also allocating
      space for our callee (and our own register save area).  */
-  actual_fsize = compute_frame_size (size, leaf_function);
+  actual_fsize
+    = sparc_compute_frame_size (get_frame_size(), sparc_leaf_function_p);
+
+  /* Advertise that the data calculated just above are now valid.  */
+  sparc_prologue_data_valid_p = true;
 
-  if (leaf_function)
+  if (sparc_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 (sparc_leaf_function_p)
     {
       if (actual_fsize <= 4096)
-       fprintf (file, "\tsave\t%%sp, -%d, %%sp\n", actual_fsize);
+       insn = emit_insn (gen_stack_pointer_inc (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);
+         insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-4096)));
+         /* %sp is still the CFA register.  */
+         RTX_FRAME_RELATED_P (insn) = 1;
+         insn
+           = emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize)));
        }
       else
        {
-         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));
+         insn = emit_insn (gen_stack_pointer_inc (reg));
+         REG_NOTES (insn) =
+           gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                              gen_stack_pointer_inc (GEN_INT (-actual_fsize)),
+                              REG_NOTES (insn));
        }
+
+      RTX_FRAME_RELATED_P (insn) = 1;
     }
-  else /* leaf function */
+  else
     {
       if (actual_fsize <= 4096)
-       fprintf (file, "\tadd\t%%sp, -%d, %%sp\n", actual_fsize);
+       insn = 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);
+         insn = emit_insn (gen_save_register_window (GEN_INT (-4096)));
+         /* %sp is not the CFA register anymore.  */
+         emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize)));
        }
       else
        {
-         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));
+         insn = emit_insn (gen_save_register_window (reg));
        }
+
+      RTX_FRAME_RELATED_P (insn) = 1;
+      for (i=0; i < XVECLEN (PATTERN (insn), 0); i++)
+        RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, i)) = 1;
     }
 
-  if (dwarf2out_do_frame () && actual_fsize)
-    {
-      char *label = dwarf2out_cfi_label ();
+  if (num_gfregs)
+    emit_save_or_restore_regs (SORR_SAVE);
 
-      /* The canonical frame address refers to the top of the frame.  */
-      dwarf2out_def_cfa (label, (leaf_function ? STACK_POINTER_REGNUM
-                                : HARD_FRAME_POINTER_REGNUM),
-                        frame_base_offset);
+  /* Load the PIC register if needed.  */
+  if (flag_pic && crtl->uses_pic_offset_table)
+    load_pic_register (false);
+}
+/* This function generates the assembly code for function entry, which boils
+   down to emitting the necessary .register directives.  */
 
-      if (! leaf_function)
-       {
-         /* Note the register window save.  This tells the unwinder that
-            it needs to restore the window registers from the previous
-            frame's window save area at 0(cfa).  */
-         dwarf2out_window_save (label);
+static void
+sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+{
+  /* Check that the assumption we made in sparc_expand_prologue is valid.  */
+  gcc_assert (sparc_leaf_function_p == current_function_uses_only_leaf_regs);
 
-         /* The return address (-8) is now in %i7.  */
-         dwarf2out_return_reg (label, 31);
-       }
-    }
+  sparc_output_scratch_registers (file);
+}
 
-  /* 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.  */
 
-  /* Call saved registers are saved just above the outgoing argument area.  */
+void
+sparc_expand_epilogue (void)
+{
   if (num_gfregs)
-    {
-      int offset, real_offset, n_regs;
-      const char *base;
+    emit_save_or_restore_regs (SORR_RESTORE);
 
-      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 (sparc_leaf_function_p)
+    {
+      if (actual_fsize <= 4096)
+       emit_insn (gen_stack_pointer_dec (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_insn (gen_stack_pointer_dec (GEN_INT (-4096)));
+         emit_insn (gen_stack_pointer_dec (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_insn (gen_stack_pointer_dec (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.  */
+/* Return true if it is appropriate to emit `return' instructions in the
+   body of a function.  */
 
+bool
+sparc_can_use_return_insn_p (void)
+{
+  return sparc_prologue_data_valid_p
+        && (actual_fsize == 0 || !sparc_leaf_function_p);
+}
+  
+/* This function generates the assembly code for function exit.  */
+  
 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 (i.e. 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;
+  gcc_assert (GET_CODE (pat) == SET);
 
-      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);
+       gcc_assert (XEXP (pat, 1) == const1_rtx);
+       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)
+{
+  if (sparc_leaf_function_p)
+    {
+      /* This is a leaf function so we don't have to bother restoring the
+        register window, which frees us from dealing with the convoluted
+        semantics of restore/return.  We simply output the jump to the
+        return address and the insn in the delay slot (if any).  */
 
-  /* 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");
+      gcc_assert (! crtl->calls_eh_return);
 
-  if (! leaf_function)
+      return "jmp\t%%o7+%)%#";
+    }
+  else
     {
-      if (current_function_calls_eh_return)
+      /* 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 (crtl->calls_eh_return)
        {
-         if (current_function_epilogue_delay_list)
-           abort ();
-         if (SKIP_CALLERS_UNIMP_P)
-           abort ();
+         /* If the function uses __builtin_eh_return, the eh_return
+            machinery occupies the delay slot.  */
+         gcc_assert (! final_sequence);
 
-         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 (final_sequence)
        {
-         rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0));
+         rtx delay, pat;
+
+         delay = NEXT_INSN (insn);
+         gcc_assert (delay);
 
-         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);
+             return "return\t%%i7+%)%#";
            }
          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;
+             output_asm_insn ("jmp\t%%i7+%)", NULL);
+             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);
-    }
-  /* 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 ();
+        {
+         /* The delay slot is empty.  */
+         if (TARGET_V9)
+           return "return\t%%i7+%)\n\t nop";
+         else if (flag_delayed_branch)
+           return "jmp\t%%i7+%)\n\t restore";
+         else
+           return "restore\n\tjmp\t%%o7+%)\n\t nop";
+       }
+    }
+
+  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;
+  rtx operands[1];
 
-  if (num_gfregs)
-    {
-      /* Call to restore global regs might clobber
-        the delay slot. Instead of checking for this
-        output the delay slot now.  */
-      if (delay_slot)
-       {
-         rtx delay = NEXT_INSN (insn);
+  gcc_assert (flag_delayed_branch);
 
-         if (! delay)
-           abort ();
+  operands[0] = call_operand;
 
-         final_scan_insn (delay, asm_out_file, 1, 0, 1);
-         PATTERN (delay) = gen_blockage ();
-         INSN_CODE (delay) = -1;
-         delay_slot = 0;
-       }
-      output_restore_regs (asm_out_file, leaf_regs);
-    }
+  if (sparc_leaf_function_p)
+    {
+      /* This is a leaf function so we don't have to bother restoring the
+        register window.  We simply output the jump to the function and
+        the insn in the delay slot (if any).  */
 
-  operands[0] = call_operand;
+      gcc_assert (!(LEAF_SIBCALL_SLOT_RESERVED_P && final_sequence));
 
-  if (leaf_regs)
+      if (final_sequence)
+       output_asm_insn ("sethi\t%%hi(%a0), %%g1\n\tjmp\t%%g1 + %%lo(%a0)%#",
+                        operands);
+      else
+       /* Use or with rs2 %%g0 instead of mov, so that as/ld can optimize
+          it into branch if possible.  */
+       output_asm_insn ("or\t%%o7, %%g0, %%g1\n\tcall\t%a0, 0\n\t or\t%%g1, %%g0, %%o7",
+                        operands);
+    }
+  else
     {
-#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;
+      /* 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 ((actual_fsize || ! spare_slot) && delay_slot)
+      output_asm_insn ("call\t%a0, 0", operands);
+
+      if (final_sequence)
        {
          rtx delay = NEXT_INSN (insn);
+         gcc_assert (delay);
 
-         if (! delay)
-           abort ();
+         output_restore (PATTERN (delay));
 
-         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_restore (NULL_RTX);
     }
 
-  output_asm_insn ("call\t%a0, 0", operands);
-  if (delay_slot)
-    {
-      rtx delay = NEXT_INSN (insn), pat;
-
-      if (! delay)
-       abort ();
-
-      pat = PATTERN (delay);
-      if (GET_CODE (pat) != SET)
-       abort ();
-
-      operands[0] = SET_DEST (pat);
-      pat = SET_SRC (pat);
-      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);
-         output_asm_insn (" restore %r1, %r1, %Y0", operands);
-         break;
-       default:
-         operands[1] = pat;
-         output_asm_insn (" restore %%g0, %1, %Y0", operands);
-         break;
-       }
-      PATTERN (delay) = gen_blockage ();
-      INSN_CODE (delay) = -1;
-    }
-  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.
 
@@ -4321,7 +4389,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.
@@ -4338,7 +4406,80 @@ 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              any        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 aggregate types 
+conventions.  */
+
 
 /* Maximum number of int regs for args.  */
 #define SPARC_INT_ARG_MAX 6
@@ -4353,19 +4494,67 @@ output_sibcall (insn, call_operand)
    For a library call, FNTYPE is 0.  */
 
 void
-init_cumulative_args (cum, fntype, libname, indirect)
-     CUMULATIVE_ARGS *cum;
-     tree fntype;
-     rtx libname ATTRIBUTE_UNUSED;
-     int indirect 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 (const_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))
+                  || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
+                 && 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.
@@ -4380,126 +4569,125 @@ init_cumulative_args (cum, fntype, libname, indirect)
    *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
                 : SPARC_OUTGOING_INT_ARG_FIRST);
   int slotno = cum->words;
+  enum mode_class mclass;
   int regno;
 
   *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)
-    {
-    case VOIDmode :
-      /* MODE is VOIDmode when generating the actual call.
-        See emit_call_1.  */
-      return -1;
-
-    case QImode : case CQImode :
-    case HImode : case CHImode :
-    case SImode : case CSImode :
-    case DImode : case CDImode :
-    case TImode : case CTImode :
-      if (slotno >= SPARC_INT_ARG_MAX)
-       return -1;
-      regno = regbase + slotno;
-      break;
+  /* For SPARC64, objects requiring 16-byte alignment get it.  */
+  if (TARGET_ARCH64
+      && (type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode)) >= 128
+      && (slotno & 1) != 0)
+    slotno++, *ppadding = 1;
 
-    case SFmode : case SCmode :
-    case DFmode : case DCmode :
-    case TFmode : case TCmode :
-      if (TARGET_ARCH32)
+  mclass = GET_MODE_CLASS (mode);
+  if (type && TREE_CODE (type) == VECTOR_TYPE)
+    {
+      /* Vector types deserve special treatment because they are
+        polymorphic wrt their mode, depending upon whether VIS
+        instructions are enabled.  */
+      if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
        {
-         if (slotno >= SPARC_INT_ARG_MAX)
-           return -1;
-         regno = regbase + slotno;
+         /* The SPARC port defines no floating-point vector modes.  */
+         gcc_assert (mode == BLKmode);
        }
       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;
-           }
+         /* Integral vector types should either have a vector
+            mode or an integral mode, because we are guaranteed
+            by pass_by_reference that their size is not greater
+            than 16 bytes and TImode is 16-byte wide.  */
+         gcc_assert (mode != BLKmode);
+
+         /* Vector integers are handled like floats according to
+            the Sun VIS SDK.  */
+         mclass = MODE_FLOAT;
        }
-      break;
+    }
 
-    case BLKmode :
-      /* For sparc64, objects requiring 16 byte alignment get it.  */
-      if (TARGET_ARCH64)
+  switch (mclass)
+    {
+    case MODE_FLOAT:
+    case MODE_COMPLEX_FLOAT:
+    case MODE_VECTOR_INT:
+      if (TARGET_ARCH64 && TARGET_FPU && named)
        {
-         if (type && TYPE_ALIGN (type) == 128 && (slotno & 1) != 0)
-           slotno++, *ppadding = 1;
+         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 MODE_INT:
+    case MODE_COMPLEX_INT:
+      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;
+
+      gcc_assert (mode == BLKmode);
 
       if (TARGET_ARCH32
-         || (type && TREE_CODE (type) == UNION_TYPE))
+         || !type
+         || (TREE_CODE (type) != VECTOR_TYPE
+             && TREE_CODE (type) != RECORD_TYPE))
        {
          if (slotno >= SPARC_INT_ARG_MAX)
            return -1;
          regno = regbase + slotno;
        }
-      else
+      else  /* TARGET_ARCH64 && 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;
+         int intregs_p = 0, fpregs_p = 0, 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;
-               }
-           }
+         /* First see what kinds of registers we would need.  */
+         if (TREE_CODE (type) == VECTOR_TYPE)
+           fpregs_p = 1;
+         else
+           scan_record_type (type, &intregs_p, &fpregs_p, &packed_p);
+
+         /* The ABI obviously doesn't specify how packed structures
+            are passed.  These are defined to be passed in int regs
+            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
@@ -4509,7 +4697,7 @@ function_arg_slotno (cum, mode, type, named, incoming_p, pregno, ppadding)
       break;
 
     default :
-      abort ();
+      gcc_unreachable ();
     }
 
   *pregno = regno;
@@ -4520,51 +4708,50 @@ function_arg_slotno (cum, mode, type, named, incoming_p, pregno, ppadding)
 
 struct function_arg_record_value_parms
 {
-  rtx ret;
-  int slotno, named, regbase;
-  unsigned int nregs;
-  int intoffset;
+  rtx ret;             /* return expression being built.  */
+  int slotno;          /* slot number of the argument.  */
+  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 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 *));
+ (const_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));
+ (const_tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
+static rtx function_arg_record_value (const_tree, enum machine_mode, int, int, int);
+static rtx function_arg_union_value (int, enum machine_mode, int, int);
 
 /* A subroutine of function_arg_record_value.  Traverse the structure
-   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 (const_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))
@@ -4573,41 +4760,59 @@ function_arg_record_value_1 (type, startbitpos, parms)
        {
          HOST_WIDE_INT bitpos = startbitpos;
 
-         if (DECL_SIZE (field) != 0
-             && host_integerp (bit_position (field), 1))
-           bitpos += int_bit_position (field);
+         if (DECL_SIZE (field) != 0)
+           {
+             if (integer_zerop (DECL_SIZE (field)))
+               continue;
+
+             if (host_integerp (bit_position (field), 1))
+               bitpos += int_bit_position (field);
+           }
 
          /* ??? FIXME: else assume zero offset.  */
 
          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;
 
-                 intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
-                 intslots = MAX (intslots, 0);
+                 if (intslots > 0 && intslots > SPARC_INT_ARG_MAX - this_slotno)
+                   {
+                     intslots = MAX (0, SPARC_INT_ARG_MAX - this_slotno);
+                     /* We need to pass this field on the stack.  */
+                     parms->stack = 1;
+                   }
+
                  parms->nregs += intslots;
                  parms->intoffset = -1;
                }
 
              /* There's no need to check this_slotno < SPARC_FP_ARG MAX.
                 If it wasn't true we wouldn't be here.  */
-             parms->nregs += 1;
-             if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+             if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
+                 && DECL_MODE (field) == BLKmode)
+               parms->nregs += TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
+             else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+               parms->nregs += 2;
+             else
                parms->nregs += 1;
            }
          else
@@ -4623,9 +4828,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;
@@ -4654,8 +4858,8 @@ function_arg_record_value_3 (bitpos, parms)
      at the moment but may wish to revisit.  */
 
   if (intoffset % BITS_PER_WORD != 0)
-    mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
-                         MODE_INT, 0);
+    mode = smallest_mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
+                                  MODE_INT);
   else
     mode = word_mode;
 
@@ -4664,11 +4868,12 @@ function_arg_record_value_3 (bitpos, parms)
     {
       regno = parms->regbase + this_slotno;
       reg = gen_rtx_REG (mode, regno);
-      XVECEXP (parms->ret, 0, parms->nregs)
+      XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
        = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (intoffset));
 
       this_slotno += 1;
       intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1;
+      mode = word_mode;
       parms->nregs += 1;
       intslots -= 1;
     }
@@ -4681,22 +4886,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 (const_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))
     {
@@ -4704,51 +4908,64 @@ function_arg_record_value_2 (type, startbitpos, parms)
        {
          HOST_WIDE_INT bitpos = startbitpos;
 
-         if (DECL_SIZE (field) != 0
-             && host_integerp (bit_position (field), 1))
-           bitpos += int_bit_position (field);
+         if (DECL_SIZE (field) != 0)
+           {
+             if (integer_zerop (DECL_SIZE (field)))
+               continue;
+
+             if (host_integerp (bit_position (field), 1))
+               bitpos += int_bit_position (field);
+           }
 
          /* ??? FIXME: else assume zero offset.  */
 
          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;
+             int regno, nregs, pos;
              enum machine_mode mode = DECL_MODE (field);
              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;
-               case DCmode: mode = DFmode; break;
-               case TCmode: mode = TFmode; break;
-               default: break;
+
+             if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
+                 && mode == BLKmode)
+               {
+                 mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
+                 nregs = TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
                }
+             else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+               {
+                 mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
+                 nregs = 2;
+               }
+             else
+               nregs = 1;
+
+             regno = SPARC_FP_ARG_FIRST + this_slotno * 2;
+             if (GET_MODE_SIZE (mode) <= 4 && (bitpos & 32) != 0)
+               regno++;
              reg = gen_rtx_REG (mode, regno);
-             XVECEXP (parms->ret, 0, parms->nregs)
-               = gen_rtx_EXPR_LIST (VOIDmode, reg,
-                          GEN_INT (bitpos / BITS_PER_UNIT));
+             pos = bitpos / BITS_PER_UNIT;
+             XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
+               = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
              parms->nregs += 1;
-             if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+             while (--nregs > 0)
                {
                  regno += GET_MODE_SIZE (mode) / 4;
                  reg = gen_rtx_REG (mode, regno);
-                 XVECEXP (parms->ret, 0, parms->nregs)
-                   = gen_rtx_EXPR_LIST (VOIDmode, reg,
-                       GEN_INT ((bitpos + GET_MODE_BITSIZE (mode))
-                                / BITS_PER_UNIT));
+                 pos += GET_MODE_SIZE (mode);
+                 XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
+                   = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
                  parms->nregs += 1;
                }
            }
@@ -4762,13 +4979,22 @@ function_arg_record_value_2 (type, startbitpos, parms)
 }
 
 /* Used by function_arg and function_value to implement the complex
-   Sparc64 structure calling conventions.  */
+   conventions of the 64-bit ABI for passing and returning structures.
+   Return an expression valid as a return value for the two macros
+   FUNCTION_ARG and FUNCTION_VALUE.
 
+   TYPE is the data type of the argument (as a tree).
+    This is null for libcalls where that information may
+    not be available.
+   MODE is the argument's machine mode.
+   SLOTNO is the index number of the argument's slot in the parameter array.
+   NAMED is nonzero if this argument is a named parameter
+    (otherwise it is an extra parameter matching an ellipsis).
+   REGBASE is the regno of the base register for the parameter array.  */
+   
 static rtx
-function_arg_record_value (type, mode, slotno, named, regbase)
-     tree type;
-     enum machine_mode mode;
-     int slotno, named, regbase;
+function_arg_record_value (const_tree type, enum machine_mode mode,
+                          int slotno, int named, int regbase)
 {
   HOST_WIDE_INT typesize = int_size_in_bytes (type);
   struct function_arg_record_value_parms parms;
@@ -4778,12 +5004,14 @@ function_arg_record_value (type, mode, slotno, named, regbase)
   parms.slotno = slotno;
   parms.named = named;
   parms.regbase = regbase;
+  parms.stack = 0;
 
   /* 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;
@@ -4794,8 +5022,12 @@ function_arg_record_value (type, mode, slotno, named, regbase)
       intslots = (endbit - startbit) / BITS_PER_WORD;
       this_slotno = slotno + parms.intoffset / BITS_PER_WORD;
 
-      intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
-      intslots = MAX (intslots, 0);
+      if (intslots > 0 && intslots > SPARC_INT_ARG_MAX - this_slotno)
+        {
+         intslots = MAX (0, SPARC_INT_ARG_MAX - this_slotno);
+         /* We need to pass this field on the stack.  */
+         parms.stack = 1;
+        }
 
       parms.nregs += intslots;
     }
@@ -4822,23 +5054,96 @@ function_arg_record_value (type, mode, slotno, named, regbase)
       if (nregs + slotno > SPARC_INT_ARG_MAX)
        nregs = SPARC_INT_ARG_MAX - slotno;
     }
-  if (nregs == 0)
-    abort ();
+  gcc_assert (nregs != 0);
 
-  parms.ret = gen_rtx_PARALLEL (mode, rtvec_alloc (nregs));
+  parms.ret = gen_rtx_PARALLEL (mode, rtvec_alloc (parms.stack + nregs));
+
+  /* If at least one field must be passed on the stack, generate
+     (parallel [(expr_list (nil) ...) ...]) so that all fields will
+     also be passed on the stack.  We can't do much better because the
+     semantics of TARGET_ARG_PARTIAL_BYTES doesn't handle the case
+     of structures for which the fields passed exclusively in registers
+     are not at the beginning of the structure.  */
+  if (parms.stack)
+    XVECEXP (parms.ret, 0, 0)
+      = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
 
   /* 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)
-    abort ();
+  gcc_assert (parms.nregs == nregs);
 
   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 slotno,
+                         int regno)
+{
+  int nwords = ROUND_ADVANCE (size), i;
+  rtx regs;
+
+  /* See comment in previous function for empty structures.  */
+  if (nwords == 0)
+    return gen_rtx_REG (mode, regno);
+
+  if (slotno == SPARC_INT_ARG_MAX - 1)
+    nwords = 1;
+
+  regs = gen_rtx_PARALLEL (mode, rtvec_alloc (nwords));
+
+  for (i = 0; i < nwords; i++)
+    {
+      /* Unions are passed left-justified.  */
+      XVECEXP (regs, 0, i)
+       = gen_rtx_EXPR_LIST (VOIDmode,
+                            gen_rtx_REG (word_mode, regno),
+                            GEN_INT (UNITS_PER_WORD * i));
+      regno++;
+    }
+
+  return regs;
+}
+
+/* Used by function_arg and function_value to implement the conventions
+   for passing and returning large (BLKmode) vectors.
+   Return an expression valid as a return value for the two macros
+   FUNCTION_ARG and FUNCTION_VALUE.
+
+   SIZE is the size in bytes of the vector (at least 8 bytes).
+   REGNO is the FP hard register the vector will be passed in.  */
+
+static rtx
+function_arg_vector_value (int size, int regno)
+{
+  int i, nregs = size / 8;
+  rtx regs;
+
+  regs = gen_rtx_PARALLEL (BLKmode, rtvec_alloc (nregs));
+
+  for (i = 0; i < nregs; i++)
+    {
+      XVECEXP (regs, 0, i)
+       = gen_rtx_EXPR_LIST (VOIDmode,
+                            gen_rtx_REG (DImode, regno + 2*i),
+                            GEN_INT (i*8));
+    }
+
+  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,
@@ -4855,40 +5160,65 @@ 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
                 : SPARC_OUTGOING_INT_ARG_FIRST);
   int slotno, regno, padding;
-  rtx reg;
+  enum mode_class mclass = GET_MODE_CLASS (mode);
 
   slotno = function_arg_slotno (cum, mode, type, named, incoming_p,
                                &regno, &padding);
-
   if (slotno == -1)
     return 0;
 
+  /* Vector types deserve special treatment because they are polymorphic wrt
+     their mode, depending upon whether VIS instructions are enabled.  */
+  if (type && TREE_CODE (type) == VECTOR_TYPE)
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      gcc_assert ((TARGET_ARCH32 && size <= 8)
+                 || (TARGET_ARCH64 && size <= 16));
+
+      if (mode == BLKmode)
+       return function_arg_vector_value (size,
+                                         SPARC_FP_ARG_FIRST + 2*slotno);
+      else
+       mclass = MODE_FLOAT;
+    }
+
   if (TARGET_ARCH32)
+    return gen_rtx_REG (mode, regno);
+
+  /* Structures up to 16 bytes in size are passed in arg slots on the stack
+     and are promoted to registers if possible.  */
+  if (type && TREE_CODE (type) == RECORD_TYPE)
     {
-      reg = gen_rtx_REG (mode, regno);
-      return reg;
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      gcc_assert (size <= 16);
+
+      return function_arg_record_value (type, mode, slotno, named, regbase);
+    }
+
+  /* Unions up to 16 bytes in size are passed in integer registers.  */
+  else if (type && TREE_CODE (type) == UNION_TYPE)
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      gcc_assert (size <= 16);
+
+      return function_arg_union_value (size, mode, slotno, regno);
     }
 
   /* v9 fp args in reg slots beyond the int reg slots get passed in regs
      but also have the slot allocated for them.
      If no prototype is in scope fp values in register slots get passed
      in two places, either fp regs and int regs or fp regs and memory.  */
-  if ((GET_MODE_CLASS (mode) == MODE_FLOAT
-       || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
-      && SPARC_FP_REG_P (regno))
+  else if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
+          && SPARC_FP_REG_P (regno))
     {
-      reg = gen_rtx_REG (mode, regno);
+      rtx reg = gen_rtx_REG (mode, regno);
       if (cum->prototype_p || cum->libcall_p)
        {
          /* "* 2" because fp reg numbers are recorded in 4 byte
@@ -4914,7 +5244,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;
@@ -4949,39 +5279,22 @@ 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)
+  /* All other aggregate types are passed in an integer register in a mode
+     corresponding to the size of the type.  */
+  else if (type && AGGREGATE_TYPE_P (type))
     {
-      enum machine_mode mode;
-      int bytes = int_size_in_bytes (type);
-
-      if (bytes > 16)
-       abort ();
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      gcc_assert (size <= 16);
 
-      mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
-      reg = gen_rtx_REG (mode, regno);
-    }
-  else
-    {
-      /* Scalar or complex int.  */
-      reg = gen_rtx_REG (mode, regno);
+      mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
     }
 
-  return reg;
+  return gen_rtx_REG (mode, regno);
 }
 
-/* Handle the FUNCTION_ARG_PARTIAL_NREGS macro.
-   For an arg passed partly in registers and partly in memory,
-   this is the number of registers used.
+/* For an arg passed partly in registers and partly in memory,
+   this is the number of bytes of registers used.
    For args passed entirely in registers or entirely in memory, zero.
 
    Any arg that starts in the first 6 regs but won't entirely fit in them
@@ -4990,12 +5303,9 @@ function_arg (cum, mode, type, named, incoming_p)
    values that begin in the last fp reg [where "last fp reg" varies with the
    mode] will be split between that reg and memory.  */
 
-int
-function_arg_partial_nregs (cum, mode, type, named)
-     const CUMULATIVE_ARGS *cum;
-     enum machine_mode mode;
-     tree type;
-     int named;
+static int
+sparc_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                        tree type, bool named)
 {
   int slotno, regno, padding;
 
@@ -5010,78 +5320,92 @@ 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) * UNITS_PER_WORD;
     }
   else
     {
+      /* We are guaranteed by pass_by_reference that the size of the
+        argument is not greater than 16 bytes, so we only need to return
+        one word if the argument is partially passed in registers.  */
+
       if (type && AGGREGATE_TYPE_P (type))
        {
          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;
+           return UNITS_PER_WORD;
        }
       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 UNITS_PER_WORD;
        }
       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 UNITS_PER_WORD;
        }
-      return 0;
     }
+
+  return 0;
 }
 
-/* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
-   !v9: The SPARC ABI stipulates passing struct arguments (of any size) and
-   quad-precision floats by invisible reference.
-   v9: Aggregates greater than 16 bytes are passed by reference.
-   For Pascal, also pass arrays by reference.  */
+/* Handle the TARGET_PASS_BY_REFERENCE target hook.
+   Specify whether to pass the argument by reference.  */
 
-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, const_tree type,
+                        bool named ATTRIBUTE_UNUSED)
 {
   if (TARGET_ARCH32)
-    {
-      return ((type && AGGREGATE_TYPE_P (type))
-             || mode == TFmode || mode == TCmode);
-    }
+    /* Original SPARC 32-bit ABI says that structures and unions,
+       and quad-precision floats are passed by reference.  For Pascal,
+       also pass arrays by reference.  All other base types are passed
+       in registers.
+
+       Extended ABI (as implemented by the Sun compiler) says that all
+       complex floats are passed by reference.  Pass complex integers
+       in registers up to 8 bytes.  More generally, enforce the 2-word
+       cap for passing arguments in registers.
+
+       Vector ABI (as implemented by the Sun VIS SDK) says that vector
+       integers are passed like floats of the same size, that is in
+       registers up to 8 bytes.  Pass all vector floats by reference
+       like structure and unions.  */
+    return ((type && (AGGREGATE_TYPE_P (type) || VECTOR_FLOAT_TYPE_P (type)))
+           || mode == SCmode
+           /* Catch CDImode, TFmode, DCmode and TCmode.  */
+           || GET_MODE_SIZE (mode) > 8
+           || (type
+               && TREE_CODE (type) == VECTOR_TYPE
+               && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8));
   else
-    {
-      return ((type && TREE_CODE (type) == ARRAY_TYPE)
-             /* 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));
-    }
+    /* Original SPARC 64-bit ABI says that structures and unions
+       smaller than 16 bytes are passed in registers, as well as
+       all other base types.
+       
+       Extended ABI (as implemented by the Sun compiler) says that
+       complex floats are passed in registers up to 16 bytes.  Pass
+       all complex integers in registers up to 16 bytes.  More generally,
+       enforce the 2-word cap for passing arguments in registers.
+
+       Vector ABI (as implemented by the Sun VIS SDK) says that vector
+       integers are passed like floats of the same size, that is in
+       registers (up to 16 bytes).  Pass all vector floats like structure
+       and unions.  */
+    return ((type
+            && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE)
+            && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)
+           /* Catch CTImode and TCmode.  */
+           || GET_MODE_SIZE (mode) > 16);
 }
 
 /* Handle the FUNCTION_ARG_ADVANCE macro.
@@ -5090,11 +5414,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;
 
@@ -5124,14 +5445,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
@@ -5146,73 +5459,210 @@ 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, const_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 (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
+{
+  if (TARGET_ARCH32)
+    /* Original SPARC 32-bit ABI says that structures and unions,
+       and quad-precision floats are returned in memory.  All other
+       base types are returned in registers.
+
+       Extended ABI (as implemented by the Sun compiler) says that
+       all complex floats are returned in registers (8 FP registers
+       at most for '_Complex long double').  Return all complex integers
+       in registers (4 at most for '_Complex long long').
+
+       Vector ABI (as implemented by the Sun VIS SDK) says that vector
+       integers are returned like floats of the same size, that is in
+       registers up to 8 bytes and in memory otherwise.  Return all
+       vector floats in memory like structure and unions; note that
+       they always have BLKmode like the latter.  */
+    return (TYPE_MODE (type) == BLKmode
+           || TYPE_MODE (type) == TFmode
+           || (TREE_CODE (type) == VECTOR_TYPE
+               && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8));
+  else
+    /* Original SPARC 64-bit ABI says that structures and unions
+       smaller than 32 bytes are returned in registers, as well as
+       all other base types.
+       
+       Extended ABI (as implemented by the Sun compiler) says that all
+       complex floats are returned in registers (8 FP registers at most
+       for '_Complex long double').  Return all complex integers in
+       registers (4 at most for '_Complex TItype').
+
+       Vector ABI (as implemented by the Sun VIS SDK) says that vector
+       integers are returned like floats of the same size, that is in
+       registers.  Return all vector floats like structure and unions;
+       note that they always have BLKmode like the latter.  */
+    return ((TYPE_MODE (type) == BLKmode
+            && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32));
+}
+
+/* Handle the TARGET_STRUCT_VALUE target hook.
+   Return where to find the structure return value address.  */
+
+static rtx
+sparc_struct_value_rtx (tree fndecl, int incoming)
+{
+  if (TARGET_ARCH64)
+    return 0;
+  else
+    {
+      rtx mem;
+
+      if (incoming)
+       mem = gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx,
+                                                STRUCT_VALUE_OFFSET));
+      else
+       mem = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
+                                                STRUCT_VALUE_OFFSET));
+
+      /* Only follow the SPARC ABI for fixed-size structure returns. 
+         Variable size structure returns are handled per the normal 
+         procedures in GCC. This is enabled by -mstd-struct-return */
+      if (incoming == 2 
+         && sparc_std_struct_return
+         && TYPE_SIZE_UNIT (TREE_TYPE (fndecl))
+         && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (fndecl))) == INTEGER_CST)
+       {
+         /* We must check and adjust the return address, as it is
+            optional as to whether the return object is really
+            provided.  */
+         rtx ret_rtx = gen_rtx_REG (Pmode, 31);
+         rtx scratch = gen_reg_rtx (SImode);
+         rtx endlab = gen_label_rtx (); 
+
+         /* Calculate the return object size */
+         tree size = TYPE_SIZE_UNIT (TREE_TYPE (fndecl));
+         rtx size_rtx = GEN_INT (TREE_INT_CST_LOW (size) & 0xfff);
+         /* Construct a temporary return value */
+         rtx temp_val = assign_stack_local (Pmode, TREE_INT_CST_LOW (size), 0);
+
+         /* Implement SPARC 32-bit psABI callee returns struck checking
+            requirements: 
+           
+             Fetch the instruction where we will return to and see if
+            it's an unimp instruction (the most significant 10 bits
+            will be zero).  */
+         emit_move_insn (scratch, gen_rtx_MEM (SImode,
+                                               plus_constant (ret_rtx, 8)));
+         /* Assume the size is valid and pre-adjust */
+         emit_insn (gen_add3_insn (ret_rtx, ret_rtx, GEN_INT (4)));
+         emit_cmp_and_jump_insns (scratch, size_rtx, EQ, const0_rtx, SImode, 0, endlab);
+         emit_insn (gen_sub3_insn (ret_rtx, ret_rtx, GEN_INT (4)));
+         /* Assign stack temp: 
+            Write the address of the memory pointed to by temp_val into
+            the memory pointed to by mem */
+         emit_move_insn (mem, XEXP (temp_val, 0));
+         emit_label (endlab);
+       }
+
+      set_mem_alias_set (mem, struct_value_alias_set);
+      return mem;
+    }
 }
 
 /* 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 (const_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);
+  enum mode_class mclass = GET_MODE_CLASS (mode);
+  int regno;
+
+  /* Vector types deserve special treatment because they are polymorphic wrt
+     their mode, depending upon whether VIS instructions are enabled.  */
+  if (type && TREE_CODE (type) == VECTOR_TYPE)
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      gcc_assert ((TARGET_ARCH32 && size <= 8)
+                 || (TARGET_ARCH64 && size <= 32));
+
+      if (mode == BLKmode)
+       return function_arg_vector_value (size,
+                                         SPARC_FP_ARG_FIRST);
+      else
+       mclass = MODE_FLOAT;
+    }
 
   if (TARGET_ARCH64 && type)
     {
+      /* Structures up to 32 bytes in size are returned in registers.  */
       if (TREE_CODE (type) == RECORD_TYPE)
        {
-         /* Structures up to 32 bytes in size are passed in registers,
-            promoted to fp registers where possible.  */
-
-         if (int_size_in_bytes (type) > 32)
-           abort (); /* shouldn't get here */
+         HOST_WIDE_INT size = int_size_in_bytes (type);
+         gcc_assert (size <= 32);
 
          return function_arg_record_value (type, mode, 0, 1, regbase);
        }
+
+      /* Unions up to 32 bytes in size are returned in integer registers.  */
+      else if (TREE_CODE (type) == UNION_TYPE)
+       {
+         HOST_WIDE_INT size = int_size_in_bytes (type);
+         gcc_assert (size <= 32);
+
+         return function_arg_union_value (size, mode, 0, regbase);
+       }
+
+      /* Objects that require it are returned in FP registers.  */
+      else if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
+       ;
+
+      /* All other aggregate types are returned in an integer register in a
+        mode corresponding to the size of the type.  */
       else if (AGGREGATE_TYPE_P (type))
        {
          /* All other aggregate types are passed in an integer register
             in a mode corresponding to the size of the type.  */
-         HOST_WIDE_INT bytes = int_size_in_bytes (type);
-
-         if (bytes > 32)
-           abort ();
-
-         mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
+         HOST_WIDE_INT size = int_size_in_bytes (type);
+         gcc_assert (size <= 32);
+
+         mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
+
+         /* ??? We probably should have made the same ABI change in
+            3.4.0 as the one we made for unions.   The latter was
+            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 (size, mode, 0, regbase);
+         else
+           mclass = MODE_INT;
        }
+
+      /* This must match PROMOTE_FUNCTION_MODE.  */
+      else if (mclass == 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 ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT) && TARGET_FPU)
+    regno = SPARC_FP_ARG_FIRST;
   else
-    regno = BASE_OUTGOING_VALUE_REG (mode);
+    regno = regbase;
 
   return gen_rtx_REG (mode, regno);
 }
@@ -5221,14 +5671,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;
+  int first_reg = crtl->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,
@@ -5236,7 +5686,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,
@@ -5246,151 +5696,169 @@ sparc_builtin_saveregs ()
   return address;
 }
 
-/* Implement `va_start' for varargs and stdarg.  */
+/* Implement `va_start' for stdarg.  */
 
-void
-sparc_va_start (stdarg_p, valist, nextarg)
-     int stdarg_p ATTRIBUTE_UNUSED;
-     tree valist;
-     rtx nextarg;
+static void
+sparc_va_start (tree valist, rtx nextarg)
 {
   nextarg = expand_builtin_saveregs ();
-  std_expand_builtin_va_start (1, valist, nextarg);
+  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, gimple_seq *pre_p,
+                      gimple_seq *post_p)
 {
   HOST_WIDE_INT size, rsize, align;
   tree addr, incr;
-  rtx addr_rtx;
-  int indirect = 0;
+  bool indirect;
+  tree ptrtype = build_pointer_type (type);
 
-  /* Round up sizeof(type) to a word.  */
-  size = int_size_in_bytes (type);
-  rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
-  align = 0;
-
-  if (TARGET_ARCH64)
+  if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
     {
-      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 left-justified in their slots.  */
+         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 (POINTER_PLUS_EXPR, ptr_type_node, incr,
+                         size_int (align - 1));
+      incr = fold_convert (sizetype, incr);
+      incr = fold_build2 (BIT_AND_EXPR, sizetype, incr,
+                         size_int (-align));
+      incr = fold_convert (ptr_type_node, incr);
     }
 
-  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 (POINTER_PLUS_EXPR, ptr_type_node, incr,
+                       size_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_va_arg_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));
-      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_call_expr (implicit_built_in_decls[BUILT_IN_MEMCPY], 3,
+                                  dest_addr,
+                                  addr,
+                                  size_int (rsize));
+
+      gimplify_and_add (copy, pre_p);
+      addr = dest_addr;
     }
+  else
+    addr = fold_convert (ptrtype, addr);
 
-  if (indirect)
+  incr = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, incr, size_int (rsize));
+  gimplify_assign (valist, incr, post_p);
+
+  return build_va_arg_indirect_ref (addr);
+}
+\f
+/* Implement the TARGET_VECTOR_MODE_SUPPORTED_P target hook.
+   Specify whether the vector mode is supported by the hardware.  */
+
+static bool
+sparc_vector_mode_supported_p (enum machine_mode mode)
+{
+  return TARGET_VIS && VECTOR_MODE_P (mode) ? true : false;
+}
+\f
+/* Return the string to output an unconditional branch to LABEL, which is
+   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 v9_form = false;
+  char *p;
+
+  if (TARGET_V9 && INSN_ADDRESSES_SET_P ())
     {
-      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 ());
+      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;
     }
 
-  return addr_rtx;
+  if (v9_form)
+    strcpy (string, "ba%*,pt\t%%xcc, ");
+  else
+    strcpy (string, "b%*\t");
+
+  p = strchr (string, '\0');
+  *p++ = '%';
+  *p++ = 'l';
+  *p++ = '0' + label;
+  *p++ = '%';
+  *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.
 
-   REVERSED is non-zero if we should reverse the sense of the comparison.
-
-   ANNUL is non-zero if we should generate an annulling branch.
+   DEST is the destination insn (i.e. the label), INSN is the source.
 
-   NOOP is non-zero if we have to follow this branch by a noop.
+   REVERSED is nonzero if we should reverse the sense of the comparison.
 
-   INSN, if set, is the insn.  */
+   ANNUL is nonzero if we should generate an annulling branch.  */
 
-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,
+               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);
@@ -5406,7 +5874,7 @@ output_cbranch (op, dest, label, reversed, annul, noop, insn)
      to
 
      be,pn %xcc, .+12
-     nop
+      nop
      ba .LC30
 
      and
@@ -5416,10 +5884,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
@@ -5479,7 +5947,7 @@ output_cbranch (op, dest, label, reversed, annul, noop, insn)
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       /* ??? !v9: FP branches cannot be preceded by another floating point
@@ -5534,7 +6002,7 @@ output_cbranch (op, dest, label, reversed, annul, noop, insn)
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
       strcpy (string, branch);
     }
@@ -5549,9 +6017,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;
@@ -5573,17 +6039,14 @@ output_cbranch (op, dest, label, reversed, annul, noop, insn)
          labelno = v9_fcc_labelno;
          if (v8)
            {
-             if (REGNO (cc_reg) == SPARC_FCC_REG)
-               labelno = "";
-             else
-               abort ();
+             gcc_assert (REGNO (cc_reg) == SPARC_FCC_REG);
+             labelno = "";
            }
        }
       else if (mode == CCXmode || mode == CCX_NOOVmode)
        {
          labelno = "%%xcc, ";
-         if (v8)
-           abort ();
+         gcc_assert (! v8);
        }
       else
        {
@@ -5601,6 +6064,9 @@ output_cbranch (op, dest, label, reversed, annul, noop, insn)
          spaces -= 3;
        }
     }
+  else
+    labelno = "";
+
   if (spaces > 0)
     *p++ = '\t';
   else
@@ -5609,61 +6075,63 @@ output_cbranch (op, dest, label, reversed, annul, noop, insn)
   p = strchr (p, '\0');
   if (far)
     {
-      strcpy (p, ".+12\n\tnop\n\tb\t");
-      if (annul || noop)
+      strcpy (p, ".+12\n\t nop\n\tb\t");
+      /* Skip the next insn if requested or
+        if we know that it will be a nop.  */
+      if (annul || ! final_sequence)
         p[3] = '6';
-      p += 13;
+      p += 14;
     }
   *p++ = '%';
   *p++ = 'l';
-  /* Set the char indicating the number of the operand containing the
-     label_ref.  */
   *p++ = label + '0';
+  *p++ = '%';
+  *p++ = '#';
   *p = '\0';
-  if (noop)
-    strcpy (p, "\n\tnop");
 
   return string;
 }
 
 /* Emit a library call comparison between floating point X and Y.
-   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).
+   COMPARISON is the operator to compare with (EQ, NE, GT, etc).
+   Return the new operator to be used in the comparison sequence.
+
    TARGET_ARCH64 uses _Qp_* functions, which use pointers to TFmode
    values as arguments instead of the TFmode registers themselves,
    that's why we cannot call emit_float_lib_cmp.  */
-void
-sparc_emit_float_lib_cmp (x, y, comparison)
-     rtx x, y;
-     enum rtx_code comparison;
+
+enum rtx_code
+sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
 {
   const char *qpfunc;
   rtx slot0, slot1, result, tem, tem2;
   enum machine_mode mode;
+  enum rtx_code new_comparison;
 
   switch (comparison)
     {
     case EQ:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_feq" : "_Q_feq";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_feq" : "_Q_feq");
       break;
 
     case NE:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_fne" : "_Q_fne";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_fne" : "_Q_fne");
       break;
 
     case GT:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_fgt" : "_Q_fgt";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_fgt" : "_Q_fgt");
       break;
 
     case GE:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_fge" : "_Q_fge";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_fge" : "_Q_fge");
       break;
 
     case LT:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_flt" : "_Q_flt";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_flt" : "_Q_flt");
       break;
 
     case LE:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_fle" : "_Q_fle";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_fle" : "_Q_fle");
       break;
 
     case ORDERED:
@@ -5674,37 +6142,35 @@ sparc_emit_float_lib_cmp (x, y, comparison)
     case UNGE:
     case UNLE:
     case LTGT:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_cmp" : "_Q_cmp";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_cmp" : "_Q_cmp");
       break;
 
     default:
-      abort();
-      break;
+      gcc_unreachable ();
     }
 
   if (TARGET_ARCH64)
     {
-      if (GET_CODE (x) != MEM)
+      if (MEM_P (x))
+       slot0 = x;
+      else
        {
          slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
-         emit_insn (gen_rtx_SET (VOIDmode, slot0, x));
+         emit_move_insn (slot0, x);
        }
-      else
-       slot0 = x;
 
-      if (GET_CODE (y) != MEM)
+      if (MEM_P (y))
+       slot1 = y;
+      else
        {
          slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
-         emit_insn (gen_rtx_SET (VOIDmode, slot1, y));
+         emit_move_insn (slot1, y);
        }
-      else
-       slot1 = y;
 
       emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL,
                         DImode, 2,
                         XEXP (slot0, 0), Pmode,
                         XEXP (slot1, 0), Pmode);
-
       mode = DImode;
     }
   else
@@ -5712,7 +6178,6 @@ sparc_emit_float_lib_cmp (x, y, comparison)
       emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL,
                         SImode, 2,
                         x, TFmode, y, TFmode);
-
       mode = SImode;
     }
 
@@ -5726,20 +6191,22 @@ sparc_emit_float_lib_cmp (x, y, comparison)
   switch (comparison)
     {
     default:
-      emit_cmp_insn (result, const0_rtx, NE, NULL_RTX, mode, 0);
+      new_comparison = NE;
+      emit_cmp_insn (result, const0_rtx, new_comparison, NULL_RTX, mode, 0);
       break;
     case ORDERED:
     case UNORDERED:
-      emit_cmp_insn (result, GEN_INT(3), comparison == UNORDERED ? EQ : NE,
-                    NULL_RTX, mode, 0);
+      new_comparison = (comparison == UNORDERED ? EQ : NE);
+      emit_cmp_insn (result, GEN_INT(3), new_comparison, NULL_RTX, mode, 0);
       break;
     case UNGT:
     case UNGE:
-      emit_cmp_insn (result, const1_rtx,
-                    comparison == UNGT ? GT : NE, NULL_RTX, mode, 0);
+      new_comparison = (comparison == UNGT ? GT : NE);
+      emit_cmp_insn (result, const1_rtx, new_comparison, NULL_RTX, mode, 0);
       break;
     case UNLE:
-      emit_cmp_insn (result, const2_rtx, NE, NULL_RTX, mode, 0);
+      new_comparison = NE;
+      emit_cmp_insn (result, const2_rtx, new_comparison, NULL_RTX, mode, 0);
       break;
     case UNLT:
       tem = gen_reg_rtx (mode);
@@ -5747,7 +6214,8 @@ sparc_emit_float_lib_cmp (x, y, comparison)
        emit_insn (gen_andsi3 (tem, result, const1_rtx));
       else
        emit_insn (gen_anddi3 (tem, result, const1_rtx));
-      emit_cmp_insn (tem, const0_rtx, NE, NULL_RTX, mode, 0);
+      new_comparison = NE;
+      emit_cmp_insn (tem, const0_rtx, new_comparison, NULL_RTX, mode, 0);
       break;
     case UNEQ:
     case LTGT:
@@ -5761,25 +6229,24 @@ sparc_emit_float_lib_cmp (x, y, comparison)
        emit_insn (gen_andsi3 (tem2, tem, const2_rtx));
       else
        emit_insn (gen_anddi3 (tem2, tem, const2_rtx));
-      emit_cmp_insn (tem2, const0_rtx, comparison == UNEQ ? EQ : NE,
-                    NULL_RTX, mode, 0);
+      new_comparison = (comparison == UNEQ ? EQ : NE);
+      emit_cmp_insn (tem2, const0_rtx, new_comparison, NULL_RTX, mode, 0);
       break;
     }
+
+  return new_comparison;
 }
 
 /* Generate an unsigned DImode to FP conversion.  This is the same code
    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);
@@ -5803,25 +6270,63 @@ 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.
 
-   REVERSED is non-zero if we should reverse the sense of the comparison.
+   DEST is the destination insn (i.e. the label), INSN is the source.
 
-   ANNUL is non-zero if we should generate an annulling branch.
+   REVERSED is nonzero if we should reverse the sense of the comparison.
 
-   NOOP is non-zero if we have to follow this branch by a noop.  */
+   ANNUL is nonzero if we should generate an annulling branch.  */
 
-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, 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;
@@ -5836,7 +6341,7 @@ output_v9branch (op, dest, reg, label, reversed, annul, noop, insn)
      to
      
      brz,pn %g1, .+12
-     nop
+      nop
      ba,pt %xcc, .LC30
      
      and
@@ -5846,7 +6351,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;
@@ -5856,8 +6361,7 @@ output_v9branch (op, dest, reg, label, reversed, annul, noop, insn)
     code = reverse_condition (code);
 
   /* Only 64 bit versions of these instructions exist.  */
-  if (mode != DImode)
-    abort ();
+  gcc_assert (mode == DImode);
 
   /* Start by writing the branch condition.  */
 
@@ -5888,7 +6392,7 @@ output_v9branch (op, dest, reg, label, reversed, annul, noop, insn)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   p = strchr (string, '\0');
@@ -5927,10 +6431,12 @@ output_v9branch (op, dest, reg, label, reversed, annul, noop, insn)
            veryfar = 0;
        }
 
-      strcpy (p, ".+12\n\tnop\n\t");
-      if (annul || noop)
+      strcpy (p, ".+12\n\t nop\n\t");
+      /* Skip the next insn if requested or
+        if we know that it will be a nop.  */
+      if (annul || ! final_sequence)
         p[3] = '6';
-      p += 11;
+      p += 12;
       if (veryfar)
        {
          strcpy (p, "b\t");
@@ -5945,11 +6451,10 @@ output_v9branch (op, dest, reg, label, reversed, annul, noop, insn)
   *p++ = '%';
   *p++ = 'l';
   *p++ = '0' + label;
+  *p++ = '%';
+  *p++ = '#';
   *p = '\0';
 
-  if (noop)
-    strcpy (p, "\n\tnop");
-
   return string;
 }
 
@@ -5959,9 +6464,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;
@@ -5978,7 +6481,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:
@@ -6045,11 +6548,11 @@ 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;
 
-  if (regs_ever_live[15] != last_order_nonleaf)
+  if (df_regs_ever_live_p (15) != last_order_nonleaf)
     {
       last_order_nonleaf = !last_order_nonleaf;
       memcpy ((char *) reg_alloc_order,
@@ -6062,13 +6565,10 @@ 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)
-    abort ();
+  gcc_assert (reload_completed);
 
   /* We must have an offsettable memory reference.  */
   if (! offsettable_memref_p (mem))
@@ -6085,12 +6585,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;
@@ -6107,8 +6606,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) 
@@ -6156,12 +6654,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))
@@ -6221,27 +6718,54 @@ mems_ok_for_ldd_peep (mem1, mem2, dependent_reg_rtx)
   if (INTVAL (XEXP (addr2, 1)) != offset1 + 4)
     return 0;
 
-  /* All the tests passed.  addr1 and addr2 are valid for ldd and std
-     instructions.  */
+  /* All the tests passed.  addr1 and addr2 are valid for ldd and std
+     instructions.  */
+  return 1;
+}
+
+/* Return 1 if reg is a pseudo, or is the first register in
+   a hard register pair.  This makes it suitable for use in
+   ldd and std insns.  */
+
+int
+register_ok_for_ldd (rtx reg)
+{
+  /* We might have been passed a SUBREG.  */
+  if (!REG_P (reg))
+    return 0;
+
+  if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
+    return (REGNO (reg) % 2 == 0);
+
   return 1;
 }
 
-/* Return 1 if reg is a pseudo, or is the first register in 
-   a hard register pair.  This makes it a candidate for use in
-   ldd and std insns.  */
+/* Return 1 if OP is a memory whose address is known to be
+   aligned to 8-byte boundary, or a pseudo during reload.
+   This makes it suitable for use in ldd and std insns.  */
 
 int
-register_ok_for_ldd (reg)
-     rtx reg;
+memory_ok_for_ldd (rtx op)
 {
-  /* We might have been passed a SUBREG.  */
-  if (GET_CODE (reg) != REG) 
+  if (MEM_P (op))
+    {
+      /* In 64-bit mode, we assume that the address is word-aligned.  */
+      if (TARGET_ARCH32 && !mem_min_alignment (op, 8))
+       return 0;
+
+      if ((reload_in_progress || reload_completed)
+         && !strict_memory_address_p (Pmode, XEXP (op, 0)))
+       return 0;
+    }
+  else if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)
+    {
+      if (!(reload_in_progress && reg_renumber [REGNO (op)] < 0))
+       return 0;
+    }
+  else
     return 0;
 
-  if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
-    return (REGNO (reg) % 2 == 0);
-  else 
-    return 1;
+  return 1;
 }
 \f
 /* Print operand X (an rtx) in assembler syntax to file FILE.
@@ -6249,46 +6773,65 @@ 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)
     {
     case '#':
-      /* Output a 'nop' if there's nothing for the delay slot.  */
-      if (dbr_sequence_length () == 0)
+      /* Output an insn in a delay slot.  */
+      if (final_sequence)
+        sparc_indent_opcode = 1;
+      else
        fputs ("\n\t nop", file);
       return;
     case '*':
       /* Output an annul flag if there's nothing for the delay slot and we
-        are optimizing.  This is always used with '(' below.  */
-      /* Sun OS 4.1.1 dbx can't handle an annulled unconditional branch;
-        this is a dbx bug.  So, we only do this when optimizing.  */
-      /* On UltraSPARC, a branch in a delay slot causes a pipeline flush.
+        are optimizing.  This is always used with '(' below.
+         Sun OS 4.1.1 dbx can't handle an annulled unconditional branch;
+        this is a dbx bug.  So, we only do this when optimizing.
+         On UltraSPARC, a branch in a delay slot causes a pipeline flush.
         Always emit a nop in case the next instruction is a branch.  */
-      if (dbr_sequence_length () == 0
-         && (optimize && (int)sparc_cpu < PROCESSOR_V9))
+      if (! final_sequence && (optimize && (int)sparc_cpu < PROCESSOR_V9))
        fputs (",a", file);
       return;
     case '(':
       /* Output a 'nop' if there's nothing for the delay slot and we are
         not optimizing.  This is always used with '*' above.  */
-      if (dbr_sequence_length () == 0
-         && ! (optimize && (int)sparc_cpu < PROCESSOR_V9))
+      if (! final_sequence && ! (optimize && (int)sparc_cpu < PROCESSOR_V9))
        fputs ("\n\t nop", file);
+      else if (final_sequence)
+        sparc_indent_opcode = 1;
+      return;
+    case ')':
+      /* Output the right displacement from the saved PC on function return.
+        The caller may have placed an "unimp" insn immediately after the call
+        so we have to account for it.  This insn is used in the 32-bit ABI
+        when calling a function that returns a non zero-sized structure. The
+        64-bit ABI doesn't have it.  Be careful to have this test be the same
+        as that used on the call. The exception here is that when 
+        sparc_std_struct_return is enabled, the psABI is followed exactly
+        and the adjustment is made by the code in sparc_struct_value_rtx. 
+        The call emitted is the same when sparc_std_struct_return is 
+        present. */
+     if (! TARGET_ARCH64
+        && cfun->returns_struct
+        && ! sparc_std_struct_return
+        && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))
+            == INTEGER_CST)
+        && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))))
+       fputs ("12", file);
+      else
+        fputc ('8', file);
       return;
     case '_':
       /* Output the Embedded Medium/Anywhere code model base register.  */
       fputs (EMBMEDANY_BASE_REG, file);
       return;
-    case '@':
-      /* Print out what we are using as the frame pointer.  This might
-        be %fp, or might be %sp+offset.  */
-      /* ??? What if offset is too big? Perhaps the caller knows it isn't? */
-      fprintf (file, "%s+%d", frame_base_name, frame_base_offset);
+    case '&':
+      /* Print some local dynamic TLS name.  */
+      assemble_name (file, get_some_local_dynamic_name ());
       return;
+
     case 'Y':
       /* Adjust the operand to take into account a RESTORE operation.  */
       if (GET_CODE (x) == CONST_INT)
@@ -6342,7 +6885,7 @@ print_operand (file, x, code)
          else if (GET_MODE (x) == CCXmode)
            fputs ("%xcc", file);
          else
-           abort ();
+           gcc_unreachable ();
        }
       else
        /* %fccN register */
@@ -6462,6 +7005,24 @@ print_operand (file, x, code)
       output_address (XEXP (x, 0));
       return;
 
+    case 's':
+      {
+       /* Print a sign-extended 32-bit value.  */
+       HOST_WIDE_INT i;
+       if (GET_CODE(x) == CONST_INT)
+         i = INTVAL (x);
+       else if (GET_CODE(x) == CONST_DOUBLE)
+         i = CONST_DOUBLE_LOW (x);
+       else
+         {
+           output_operand_lossage ("invalid %%s operand");
+           return;
+         }
+       i = trunc_int_for_mode (i, SImode);
+       fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
+       return;
+      }
+
     case 0:
       /* Do nothing special.  */
       break;
@@ -6519,10 +7080,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.  */
@@ -6548,10 +7106,6 @@ sparc_assemble_integer (x, size, aligned_p)
    what kind of result this function returns.  For non-C types, we pick
    the closest C type.  */
 
-#ifndef CHAR_TYPE_SIZE
-#define CHAR_TYPE_SIZE BITS_PER_UNIT
-#endif
-
 #ifndef SHORT_TYPE_SIZE
 #define SHORT_TYPE_SIZE (BITS_PER_UNIT * 2)
 #endif
@@ -6581,8 +7135,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;
@@ -6635,7 +7188,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
@@ -6645,16 +7198,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
@@ -6677,15 +7230,13 @@ sparc_type_code (type)
             existing front-ends.  */
          return (qualifiers | 7);      /* Who knows? */
 
-       case CHAR_TYPE:         /* GNU Pascal CHAR type.  Not used in C.  */
-       case BOOLEAN_TYPE:      /* GNU Fortran BOOLEAN type.  */
-       case FILE_TYPE:         /* GNU Pascal FILE type.  */
-       case SET_TYPE:          /* GNU Pascal SET type.  */
+       case VECTOR_TYPE:
+       case BOOLEAN_TYPE:      /* Boolean truth value type.  */
        case LANG_TYPE:         /* ? */
          return qualifiers;
   
        default:
-         abort ();             /* Not a type! */
+         gcc_unreachable ();           /* Not a type! */
         }
     }
 
@@ -6706,10 +7257,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
@@ -6719,10 +7269,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)),
@@ -6732,781 +7278,94 @@ sparc_initialize_trampoline (tramp, fnaddr, cxt)
                   GEN_INT (trunc_int_for_mode (0x03000000, SImode)),
                   NULL_RTX, 1, OPTAB_DIRECT));
 
-  emit_move_insn
-    (gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
-     expand_binop (SImode, ior_optab,
-                  expand_shift (RSHIFT_EXPR, SImode, cxt,
-                                size_int (10), 0, 1),
-                  GEN_INT (trunc_int_for_mode (0x05000000, SImode)),
-                  NULL_RTX, 1, OPTAB_DIRECT));
-
-  emit_move_insn
-    (gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
-     expand_binop (SImode, ior_optab,
-                  expand_and (SImode, fnaddr, GEN_INT (0x3ff), NULL_RTX),
-                  GEN_INT (trunc_int_for_mode (0x81c06000, SImode)),
-                  NULL_RTX, 1, OPTAB_DIRECT));
-
-  emit_move_insn
-    (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
-     expand_binop (SImode, ior_optab,
-                  expand_and (SImode, cxt, GEN_INT (0x3ff), NULL_RTX),
-                  GEN_INT (trunc_int_for_mode (0x8410a000, SImode)),
-                  NULL_RTX, 1, OPTAB_DIRECT));
-
-  /* On UltraSPARC a flush flushes an entire cache line.  The trampoline is
-     aligned on a 16 byte boundary so one flush clears it all.  */
-  emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, tramp))));
-  if (sparc_cpu != PROCESSOR_ULTRASPARC)
-    emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode,
-                                                    plus_constant (tramp, 8)))));
-}
-
-/* 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;
-{
-#ifdef TRANSFER_FROM_TRAMPOLINE
-  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"),
-                     LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
-#endif
-
-  /*
-       rd      %pc, %g1
-       ldx     [%g1+24], %g5
-       jmp     %g5
-       ldx     [%g1+16], %g5
-       +16 bytes data
-   */
-
-  emit_move_insn (gen_rtx_MEM (SImode, tramp),
-                 GEN_INT (trunc_int_for_mode (0x83414000, SImode)));
-  emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
-                 GEN_INT (trunc_int_for_mode (0xca586018, SImode)));
-  emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
-                 GEN_INT (trunc_int_for_mode (0x81c14000, SImode)));
-  emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
-                 GEN_INT (trunc_int_for_mode (0xca586010, SImode)));
-  emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 16)), cxt);
-  emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 24)), fnaddr);
-  emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, tramp))));
-
-  if (sparc_cpu != PROCESSOR_ULTRASPARC)
-    emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8)))));
-}
-\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;
-
-/* Zero structure to initialize current_frame_info.  */
-struct sparc_frame_info zero_frame_info;
-
-/* Tell prologue and epilogue if register REGNO should be saved / restored.  */
-
-#define RETURN_ADDR_REGNUM 15
-#define HARD_FRAME_POINTER_MASK (1 << (HARD_FRAME_POINTER_REGNUM))
-#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
-
-#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]))
-
-/* Return the bytes needed to compute the frame pointer from the current
-   stack pointer.  */
-
-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))
-       {
-         /* 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;
-           }
-       }
-    }
-
-  /* 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 (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;
-       }
-      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;
-  else
-    extra_size = 0;
-
-  total_size = SPARC_STACK_ALIGN (total_size);
-
-  /* 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;
-
-  /* Ok, we're done.  */
-  return total_size;
-}
-\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;
-{
-  int regno;
-
-  if (gmask == 0 && fmask == 0)
-    return;
-
-  /* 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.  */
-
-  if (gmask)
-    {
-      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]);
-
-                 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]);
-
-                 offset += UNITS_PER_WORD;
-               }
-           }
-       }
-    }
-
-  if (fmask)
-    {
-      for (regno = 32; regno <= 63; regno++)
-       {
-         if ((fmask & (1L << (regno - 32))) != 0)
-           {
-             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]);
-
-             offset += UNITS_PER_WORD;
-           }
-       }
-    }
-}
-\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");
-             fprintf (file, HOST_WIDE_INT_PRINT_DEC, size);
-             fprintf (file, ", %s\n\tsub\t%s, %s, %s\n",
-                      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");
-             fprintf (file, HOST_WIDE_INT_PRINT_DEC, size1);
-             fprintf (file, ", %s\n\tsub\t%s, %s, %s\n",
-                      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");
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC, size - size1);
-         fprintf (file, ", %s\n\tsub\t%s, %s, %s\n",
-                  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");
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC, size);
-         fprintf (file, ", %s\n", 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");
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC, size1);
-         fprintf (file, ", %s\n\tadd\t%s, %s, %s\n",
-                  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");
-             fprintf (file, HOST_WIDE_INT_PRINT_DEC, size);
-             fprintf (file, ", %s\n", 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);
-       }
+  emit_move_insn
+    (gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
+     expand_binop (SImode, ior_optab,
+                  expand_shift (RSHIFT_EXPR, SImode, cxt,
+                                size_int (10), 0, 1),
+                  GEN_INT (trunc_int_for_mode (0x05000000, SImode)),
+                  NULL_RTX, 1, OPTAB_DIRECT));
 
-      else if (size > 4095)
-       fprintf (file, "\tadd\t%s, %s, %s\n", sp_str, t1_str, sp_str);
+  emit_move_insn
+    (gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
+     expand_binop (SImode, ior_optab,
+                  expand_and (SImode, fnaddr, GEN_INT (0x3ff), NULL_RTX),
+                  GEN_INT (trunc_int_for_mode (0x81c06000, SImode)),
+                  NULL_RTX, 1, OPTAB_DIRECT));
 
-      else if (size > 0)
-       fprintf (file, "\tadd\t%s, %d, %s\n", sp_str, (int) size, sp_str);
+  emit_move_insn
+    (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
+     expand_binop (SImode, ior_optab,
+                  expand_and (SImode, cxt, GEN_INT (0x3ff), NULL_RTX),
+                  GEN_INT (trunc_int_for_mode (0x8410a000, SImode)),
+                  NULL_RTX, 1, OPTAB_DIRECT));
 
-      else
-       fprintf (file, "\tnop\n");
-    }
+  /* On UltraSPARC a flush flushes an entire cache line.  The trampoline is
+     aligned on a 16 byte boundary so one flush clears it all.  */
+  emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, tramp))));
+  if (sparc_cpu != PROCESSOR_ULTRASPARC
+      && sparc_cpu != PROCESSOR_ULTRASPARC3
+      && sparc_cpu != PROCESSOR_NIAGARA
+      && sparc_cpu != PROCESSOR_NIAGARA2)
+    emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode,
+                                                    plus_constant (tramp, 8)))));
 
-  /* Reset state info for each function.  */
-  current_frame_info = zero_frame_info;
+  /* 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
 
-  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.  */
+/* 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.  */
 
-int
-sparc_flat_epilogue_delay_slots ()
+void
+sparc64_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
 {
-  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.  */
+  /* SPARC 64-bit trampoline:
 
-int
-sparc_flat_eligible_for_epilogue_delay (trial, slot)
-     rtx trial;
-     int slot ATTRIBUTE_UNUSED;
-{
-  rtx pat = PATTERN (trial);
+       rd      %pc, %g1
+       ldx     [%g1+24], %g5
+       jmp     %g5
+       ldx     [%g1+16], %g5
+       +16 bytes data
+   */
 
-  if (get_attr_length (trial) != 1)
-    return 0;
+  emit_move_insn (gen_rtx_MEM (SImode, tramp),
+                 GEN_INT (trunc_int_for_mode (0x83414000, SImode)));
+  emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
+                 GEN_INT (trunc_int_for_mode (0xca586018, SImode)));
+  emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
+                 GEN_INT (trunc_int_for_mode (0x81c14000, SImode)));
+  emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
+                 GEN_INT (trunc_int_for_mode (0xca586010, SImode)));
+  emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 16)), cxt);
+  emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 24)), fnaddr);
+  emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, tramp))));
 
-  if (! reg_mentioned_p (stack_pointer_rtx, pat)
-      && ! reg_mentioned_p (frame_pointer_rtx, pat))
-    return 1;
+  if (sparc_cpu != PROCESSOR_ULTRASPARC
+      && sparc_cpu != PROCESSOR_ULTRASPARC3
+      && sparc_cpu != PROCESSOR_NIAGARA
+      && sparc_cpu != PROCESSOR_NIAGARA2)
+    emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8)))));
 
-  return 0;
+  /* 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
 /* 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;
+supersparc_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
 {
   enum attr_type insn_type;
 
@@ -7567,11 +7426,7 @@ supersparc_adjust_cost (insn, link, dep_insn, cost)
 }
 
 static int
-hypersparc_adjust_cost (insn, link, dep_insn, cost)
-     rtx insn;
-     rtx link;
-     rtx dep_insn;
-     int cost;
+hypersparc_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
 {
   enum attr_type insn_type, dep_type;
   rtx pat = PATTERN(insn);
@@ -7648,1422 +7503,1525 @@ hypersparc_adjust_cost (insn, link, dep_insn, cost)
 }
 
 static int
-ultrasparc_adjust_cost (insn, link, dep_insn, cost)
-     rtx insn;
-     rtx link;
-     rtx dep_insn;
-     int cost;
+sparc_adjust_cost(rtx insn, rtx link, rtx dep, 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);
-
-  /* Nothing issues in parallel with integer multiplies, so
-     mark as zero cost since the scheduler can not do anything
-     about it.  */
-  if (insn_type == TYPE_IMUL || insn_type == TYPE_IDIV)
-    return 0;
-
-#define SLOW_FP(dep_type) \
-(dep_type == TYPE_FPSQRTS || dep_type == TYPE_FPSQRTD || \
- dep_type == TYPE_FPDIVS || dep_type == TYPE_FPDIVD)
-
-  switch (REG_NOTE_KIND (link))
+  switch (sparc_cpu)
     {
-    case 0:
-      /* Data dependency; DEP_INSN writes a register that INSN reads some
-        cycles later.  */
-
-      if (dep_type == TYPE_CMOVE)
-       {
-         /* Instructions that read the result of conditional moves cannot
-            be in the same group or the following group.  */
-         return cost + 1;
-       }
-
-      switch (insn_type)
-       {
-         /* UltraSPARC can dual issue a store and an instruction setting
-            the value stored, except for divide and square root.  */
-       case TYPE_FPSTORE:
-         if (! SLOW_FP (dep_type))
-           return 0;
-         return cost;
-
-       case TYPE_STORE:
-         if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
-           return cost;
-
-         if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
-           /* The dependency between the two instructions is on the data
-              that is being stored.  Assume that the address of the store
-              is not also dependent.  */
-           return 0;
-         return cost;
-
-       case TYPE_LOAD:
-       case TYPE_SLOAD:
-       case TYPE_FPLOAD:
-         /* A load does not return data until at least 11 cycles after
-            a store to the same location.  3 cycles are accounted for
-            in the load latency; add the other 8 here.  */
-         if (dep_type == TYPE_STORE || dep_type == TYPE_FPSTORE)
-           {
-             /* If the addresses are not equal this may be a false
-                dependency because pointer aliasing could not be
-                determined.  Add only 2 cycles in that case.  2 is
-                an arbitrary compromise between 8, which would cause
-                the scheduler to generate worse code elsewhere to
-                compensate for a dependency which might not really
-                exist, and 0.  */
-             if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET
-                 || GET_CODE (SET_SRC (pat)) != MEM
-                 || GET_CODE (SET_DEST (dep_pat)) != MEM
-                 || ! rtx_equal_p (XEXP (SET_SRC (pat), 0),
-                                   XEXP (SET_DEST (dep_pat), 0)))
-               return cost + 2;
-
-             return cost + 8;
-           }
-         return cost;
-
-       case TYPE_BRANCH:
-         /* Compare to branch latency is 0.  There is no benefit from
-            separating compare and branch.  */
-         if (dep_type == TYPE_COMPARE)
-           return 0;
-         /* Floating point compare to branch latency is less than
-            compare to conditional move.  */
-         if (dep_type == TYPE_FPCMP)
-           return cost - 1;
-         return cost;
-
-       case TYPE_FPCMOVE:
-         /* FMOVR class instructions can not issue in the same cycle
-            or the cycle after an instruction which writes any
-            integer register.  Model this as cost 2 for dependent
-            instructions.  */
-         if (dep_type == TYPE_IALU
-             && cost < 2)
-           return 2;
-         /* Otherwise check as for integer conditional moves.  */
-
-       case TYPE_CMOVE:
-         /* Conditional moves involving integer registers wait until
-            3 cycles after loads return data.  The interlock applies
-            to all loads, not just dependent loads, but that is hard
-            to model.  */
-         if (dep_type == TYPE_LOAD || dep_type == TYPE_SLOAD)
-           return cost + 3;
-         return cost;
-
-       default:
-         break;
-       }
+    case PROCESSOR_SUPERSPARC:
+      cost = supersparc_adjust_cost (insn, link, dep, cost);
       break;
-
-    case REG_DEP_ANTI:
-      /* Divide and square root lock destination registers for full latency.  */
-      if (! SLOW_FP (dep_type))
-       return 0;
+    case PROCESSOR_HYPERSPARC:
+    case PROCESSOR_SPARCLITE86X:
+      cost = hypersparc_adjust_cost (insn, link, dep, cost);
       break;
-
-    case REG_DEP_OUTPUT:
-      /* IEU and FPU instruction that have the same destination
-        register cannot be grouped together.  */
-      return cost + 1;
-
     default:
       break;
     }
-
-  /* Other costs not accounted for:
-     - Single precision floating point loads lock the other half of
-       the even/odd register pair.
-     - Several hazards associated with ldd/std are ignored because these
-       instructions are rarely generated for V9.
-     - The floating point pipeline can not have both a single and double
-       precision operation active at the same time.  Format conversions
-       and graphics instructions are given honorary double precision status.
-     - call and jmpl are always the first instruction in a group.  */
-
   return cost;
+}
 
-#undef SLOW_FP
+static void
+sparc_sched_init (FILE *dump ATTRIBUTE_UNUSED,
+                 int sched_verbose ATTRIBUTE_UNUSED,
+                 int max_ready ATTRIBUTE_UNUSED)
+{
+}
+  
+static int
+sparc_use_sched_lookahead (void)
+{
+  if (sparc_cpu == PROCESSOR_NIAGARA
+      || sparc_cpu == PROCESSOR_NIAGARA2)
+    return 0;
+  if (sparc_cpu == PROCESSOR_ULTRASPARC
+      || sparc_cpu == PROCESSOR_ULTRASPARC3)
+    return 4;
+  if ((1 << sparc_cpu) &
+      ((1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) |
+       (1 << PROCESSOR_SPARCLITE86X)))
+    return 3;
+  return 0;
 }
 
 static int
-sparc_adjust_cost(insn, link, dep, cost)
-     rtx insn;
-     rtx link;
-     rtx dep;
-     int cost;
+sparc_issue_rate (void)
 {
   switch (sparc_cpu)
     {
+    case PROCESSOR_NIAGARA:
+    case PROCESSOR_NIAGARA2:
+    default:
+      return 1;
+    case PROCESSOR_V9:
+      /* Assume V9 processors are capable of at least dual-issue.  */
+      return 2;
     case PROCESSOR_SUPERSPARC:
-      cost = supersparc_adjust_cost (insn, link, dep, cost);
-      break;
+      return 3;
     case PROCESSOR_HYPERSPARC:
     case PROCESSOR_SPARCLITE86X:
-      cost = hypersparc_adjust_cost (insn, link, dep, cost);
-      break;
+      return 2;
     case PROCESSOR_ULTRASPARC:
-      cost = ultrasparc_adjust_cost (insn, link, dep, cost);
-      break;
+    case PROCESSOR_ULTRASPARC3:
+      return 4;
+    }
+}
+
+static int
+set_extends (rtx insn)
+{
+  register rtx pat = PATTERN (insn);
+
+  switch (GET_CODE (SET_SRC (pat)))
+    {
+      /* Load and some shift instructions zero extend.  */
+    case MEM:
+    case ZERO_EXTEND:
+      /* sethi clears the high bits */
+    case HIGH:
+      /* LO_SUM is used with sethi.  sethi cleared the high
+        bits and the values used with lo_sum are positive */
+    case LO_SUM:
+      /* Store flag stores 0 or 1 */
+    case LT: case LTU:
+    case GT: case GTU:
+    case LE: case LEU:
+    case GE: case GEU:
+    case EQ:
+    case NE:
+      return 1;
+    case AND:
+      {
+       rtx op0 = XEXP (SET_SRC (pat), 0);
+       rtx op1 = XEXP (SET_SRC (pat), 1);
+       if (GET_CODE (op1) == CONST_INT)
+         return INTVAL (op1) >= 0;
+       if (GET_CODE (op0) != REG)
+         return 0;
+       if (sparc_check_64 (op0, insn) == 1)
+         return 1;
+       return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
+      }
+    case IOR:
+    case XOR:
+      {
+       rtx op0 = XEXP (SET_SRC (pat), 0);
+       rtx op1 = XEXP (SET_SRC (pat), 1);
+       if (GET_CODE (op0) != REG || sparc_check_64 (op0, insn) <= 0)
+         return 0;
+       if (GET_CODE (op1) == CONST_INT)
+         return INTVAL (op1) >= 0;
+       return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
+      }
+    case LSHIFTRT:
+      return GET_MODE (SET_SRC (pat)) == SImode;
+      /* Positive integers leave the high bits zero.  */
+    case CONST_DOUBLE:
+      return ! (CONST_DOUBLE_LOW (SET_SRC (pat)) & 0x80000000);
+    case CONST_INT:
+      return ! (INTVAL (SET_SRC (pat)) & 0x80000000);
+    case ASHIFTRT:
+    case SIGN_EXTEND:
+      return - (GET_MODE (SET_SRC (pat)) == SImode);
+    case REG:
+      return sparc_check_64 (SET_SRC (pat), insn);
     default:
-      break;
+      return 0;
     }
-  return cost;
 }
 
-/* This describes the state of the UltraSPARC pipeline during
-   instruction scheduling.  */
+/* We _ought_ to have only one kind per function, but...  */
+static GTY(()) rtx sparc_addr_diff_list;
+static GTY(()) rtx sparc_addr_list;
+
+void
+sparc_defer_case_vector (rtx lab, rtx vec, int diff)
+{
+  vec = gen_rtx_EXPR_LIST (VOIDmode, lab, vec);
+  if (diff)
+    sparc_addr_diff_list
+      = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_diff_list);
+  else
+    sparc_addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_list);
+}
+
+static void 
+sparc_output_addr_vec (rtx vec)
+{
+  rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
+  int idx, vlen = XVECLEN (body, 0);
 
-#define TMASK(__x)     ((unsigned)1 << ((int)(__x)))
-#define UMASK(__x)     ((unsigned)1 << ((int)(__x)))
+#ifdef ASM_OUTPUT_ADDR_VEC_START  
+  ASM_OUTPUT_ADDR_VEC_START (asm_out_file);
+#endif
 
-enum ultra_code { NONE=0, /* no insn at all                            */
-                 IEU0,   /* shifts and conditional moves               */
-                 IEU1,   /* condition code setting insns, calls+jumps  */
-                 IEUN,   /* all other single cycle ieu insns           */
-                 LSU,    /* loads and stores                           */
-                 CTI,    /* branches                                   */
-                 FPM,    /* FPU pipeline 1, multiplies and divides     */
-                 FPA,    /* FPU pipeline 2, all other operations       */
-                 SINGLE, /* single issue instructions                  */
-                 NUM_ULTRA_CODES };
+#ifdef ASM_OUTPUT_CASE_LABEL
+  ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab),
+                        NEXT_INSN (lab));
+#else
+  (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (lab));
+#endif
 
-static enum ultra_code ultra_code_from_mask PARAMS ((int));
-static void ultra_schedule_insn PARAMS ((rtx *, rtx *, int, enum ultra_code));
+  for (idx = 0; idx < vlen; idx++)
+    {
+      ASM_OUTPUT_ADDR_VEC_ELT
+       (asm_out_file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
+    }
+    
+#ifdef ASM_OUTPUT_ADDR_VEC_END
+  ASM_OUTPUT_ADDR_VEC_END (asm_out_file);
+#endif
+}
 
-static const char *const ultra_code_names[NUM_ULTRA_CODES] = {
-  "NONE", "IEU0", "IEU1", "IEUN", "LSU", "CTI",
-  "FPM", "FPA", "SINGLE" };
+static void 
+sparc_output_addr_diff_vec (rtx vec)
+{
+  rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
+  rtx base = XEXP (XEXP (body, 0), 0);
+  int idx, vlen = XVECLEN (body, 1);
 
-struct ultrasparc_pipeline_state {
-  /* The insns in this group.  */
-  rtx group[4];
+#ifdef ASM_OUTPUT_ADDR_VEC_START  
+  ASM_OUTPUT_ADDR_VEC_START (asm_out_file);
+#endif
 
-  /* The code for each insn.  */
-  enum ultra_code codes[4];
+#ifdef ASM_OUTPUT_CASE_LABEL
+  ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab),
+                        NEXT_INSN (lab));
+#else
+  (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (lab));
+#endif
 
-  /* Which insns in this group have been committed by the
-     scheduler.  This is how we determine how many more
-     can issue this cycle.  */
-  char commit[4];
+  for (idx = 0; idx < vlen; idx++)
+    {
+      ASM_OUTPUT_ADDR_DIFF_ELT
+        (asm_out_file,
+         body,
+         CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
+         CODE_LABEL_NUMBER (base));
+    }
+    
+#ifdef ASM_OUTPUT_ADDR_VEC_END
+  ASM_OUTPUT_ADDR_VEC_END (asm_out_file);
+#endif
+}
 
-  /* How many insns in this group.  */
-  char group_size;
+static void
+sparc_output_deferred_case_vectors (void)
+{
+  rtx t;
+  int align;
 
-  /* Mask of free slots still in this group.  */
-  char free_slot_mask;
+  if (sparc_addr_list == NULL_RTX
+      && sparc_addr_diff_list == NULL_RTX)
+    return;
 
-  /* The slotter uses the following to determine what other
-     insn types can still make their way into this group.  */
-  char contents [NUM_ULTRA_CODES];
-  char num_ieu_insns;
-};
+  /* Align to cache line in the function's code section.  */
+  switch_to_section (current_function_section ());
 
-#define ULTRA_NUM_HIST 8
-static struct ultrasparc_pipeline_state ultra_pipe_hist[ULTRA_NUM_HIST];
-static int ultra_cur_hist;
-static int ultra_cycles_elapsed;
-
-#define ultra_pipe     (ultra_pipe_hist[ultra_cur_hist])
-
-/* Given TYPE_MASK compute the ultra_code it has.  */
-static enum ultra_code
-ultra_code_from_mask (type_mask)
-     int type_mask;
-{
-  if (type_mask & (TMASK (TYPE_SHIFT) | TMASK (TYPE_CMOVE)))
-    return IEU0;
-  else if (type_mask & (TMASK (TYPE_COMPARE) |
-                       TMASK (TYPE_CALL) |
-                       TMASK (TYPE_SIBCALL) |
-                       TMASK (TYPE_UNCOND_BRANCH)))
-    return IEU1;
-  else if (type_mask & TMASK (TYPE_IALU))
-    return IEUN;
-  else if (type_mask & (TMASK (TYPE_LOAD) | TMASK (TYPE_SLOAD) |
-                       TMASK (TYPE_STORE) | TMASK (TYPE_FPLOAD) |
-                       TMASK (TYPE_FPSTORE)))
-    return LSU;
-  else if (type_mask & (TMASK (TYPE_FPMUL) | TMASK (TYPE_FPDIVS) |
-                       TMASK (TYPE_FPDIVD) | TMASK (TYPE_FPSQRTS) |
-                       TMASK (TYPE_FPSQRTD)))
-    return FPM;
-  else if (type_mask & (TMASK (TYPE_FPMOVE) | TMASK (TYPE_FPCMOVE) |
-                       TMASK (TYPE_FP) | TMASK (TYPE_FPCMP)))
-    return FPA;
-  else if (type_mask & TMASK (TYPE_BRANCH))
-    return CTI;
-
-  return SINGLE;
-}
-
-/* Check INSN (a conditional move) and make sure that it's
-   results are available at this cycle.  Return 1 if the
-   results are in fact ready.  */
-static int
-ultra_cmove_results_ready_p (insn)
-     rtx insn;
-{
-  struct ultrasparc_pipeline_state *up;
-  int entry, slot;
-
-  /* If this got dispatched in the previous
-     group, the results are not ready.  */
-  entry = (ultra_cur_hist - 1) & (ULTRA_NUM_HIST - 1);
-  up = &ultra_pipe_hist[entry];
-  slot = 4;
-  while (--slot >= 0)
-    if (up->group[slot] == insn)
-      return 0;
+  align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+  if (align > 0)
+    ASM_OUTPUT_ALIGN (asm_out_file, align);
+  
+  for (t = sparc_addr_list; t ; t = XEXP (t, 1))
+    sparc_output_addr_vec (XEXP (t, 0));
+  for (t = sparc_addr_diff_list; t ; t = XEXP (t, 1))
+    sparc_output_addr_diff_vec (XEXP (t, 0));
 
-  return 1;
+  sparc_addr_list = sparc_addr_diff_list = NULL_RTX;
 }
 
-/* Walk backwards in pipeline history looking for FPU
-   operations which use a mode different than FPMODE and
-   will create a stall if an insn using FPMODE were to be
-   dispatched this cycle.  */
-static int
-ultra_fpmode_conflict_exists (fpmode)
-     enum machine_mode fpmode;
+/* Return 0 if the high 32 bits of X (the low word of X, if DImode) are
+   unknown.  Return 1 if the high bits are zero, -1 if the register is
+   sign extended.  */
+int
+sparc_check_64 (rtx x, rtx insn)
 {
-  int hist_ent;
-  int hist_lim;
+  /* 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
+     the single set and return the correct value or fail to recognize
+     it and return 0.  */
+  int set_once = 0;
+  rtx y = x;
 
-  hist_ent = (ultra_cur_hist - 1) & (ULTRA_NUM_HIST - 1);
-  if (ultra_cycles_elapsed < 4)
-    hist_lim = ultra_cycles_elapsed;
-  else
-    hist_lim = 4;
-  while (hist_lim > 0)
-    {
-      struct ultrasparc_pipeline_state *up = &ultra_pipe_hist[hist_ent];
-      int slot = 4;
+  gcc_assert (GET_CODE (x) == REG);
 
-      while (--slot >= 0)
-       {
-         rtx insn = up->group[slot];
-         enum machine_mode this_mode;
-         rtx pat;
+  if (GET_MODE (x) == DImode)
+    y = gen_rtx_REG (SImode, REGNO (x) + WORDS_BIG_ENDIAN);
 
-         if (! insn
-             || GET_CODE (insn) != INSN
-             || (pat = PATTERN (insn)) == 0
-             || GET_CODE (pat) != SET)
-           continue;
+  if (flag_expensive_optimizations
+      && df && DF_REG_DEF_COUNT (REGNO (y)) == 1)
+    set_once = 1;
 
-         this_mode = GET_MODE (SET_DEST (pat));
-         if ((this_mode != SFmode
-              && this_mode != DFmode)
-             || this_mode == fpmode)
-           continue;
+  if (insn == 0)
+    {
+      if (set_once)
+       insn = get_last_insn_anywhere ();
+      else
+       return 0;
+    }
 
-         /* If it is not FMOV, FABS, FNEG, FDIV, or FSQRT then
-            we will get a stall.  Loads and stores are independent
-            of these rules.  */
-         if (GET_CODE (SET_SRC (pat)) != ABS
-             && GET_CODE (SET_SRC (pat)) != NEG
-             && ((TMASK (get_attr_type (insn)) &
-                  (TMASK (TYPE_FPDIVS) | TMASK (TYPE_FPDIVD) |
-                   TMASK (TYPE_FPMOVE) | TMASK (TYPE_FPSQRTS) |
-                   TMASK (TYPE_FPSQRTD) |
-                    TMASK (TYPE_LOAD) | TMASK (TYPE_STORE))) == 0))
-           return 1;
+  while ((insn = PREV_INSN (insn)))
+    {
+      switch (GET_CODE (insn))
+       {
+       case JUMP_INSN:
+       case NOTE:
+         break;
+       case CODE_LABEL:
+       case CALL_INSN:
+       default:
+         if (! set_once)
+           return 0;
+         break;
+       case INSN:
+         {
+           rtx pat = PATTERN (insn);
+           if (GET_CODE (pat) != SET)
+             return 0;
+           if (rtx_equal_p (x, SET_DEST (pat)))
+             return set_extends (insn);
+           if (y && rtx_equal_p (y, SET_DEST (pat)))
+             return set_extends (insn);
+           if (reg_overlap_mentioned_p (SET_DEST (pat), y))
+             return 0;
+         }
        }
-      hist_lim--;
-      hist_ent = (hist_ent - 1) & (ULTRA_NUM_HIST - 1);
     }
-
-  /* No conflicts, safe to dispatch.  */
   return 0;
 }
 
-/* Find an instruction in LIST which has one of the
-   type attributes enumerated in TYPE_MASK.  START
-   says where to begin the search.
-
-   NOTE: This scheme depends upon the fact that we
-         have less than 32 distinct type attributes.  */
-
-static int ultra_types_avail;
-
-static rtx *
-ultra_find_type (type_mask, list, start)
-     int type_mask;
-     rtx *list;
-     int start;
+/* Returns assembly code to perform a DImode shift using
+   a 64-bit global or out register on SPARC-V8+.  */
+const char *
+output_v8plus_shift (rtx *operands, rtx insn, const char *opcode)
 {
-  int i;
-
-  /* Short circuit if no such insn exists in the ready
-     at the moment.  */
-  if ((type_mask & ultra_types_avail) == 0)
-    return 0;
-
-  for (i = start; i >= 0; i--)
-    {
-      rtx insn = list[i];
+  static char asm_code[60];
 
-      if (recog_memoized (insn) >= 0
-         && (TMASK(get_attr_type (insn)) & type_mask))
-       {
-         enum machine_mode fpmode = SFmode;
-         rtx pat = 0;
-         int slot;
-         int check_depend = 0;
-         int check_fpmode_conflict = 0;
+  /* The scratch register is only required when the destination
+     register is not a 64-bit global or out register.  */
+  if (which_alternative != 2)
+    operands[3] = operands[0];
 
-         if (GET_CODE (insn) == INSN
-             && (pat = PATTERN(insn)) != 0
-             && GET_CODE (pat) == SET
-             && !(type_mask & (TMASK (TYPE_STORE) |
-                               TMASK (TYPE_FPSTORE))))
-           {
-             check_depend = 1;
-             if (GET_MODE (SET_DEST (pat)) == SFmode
-                 || GET_MODE (SET_DEST (pat)) == DFmode)
-               {
-                 fpmode = GET_MODE (SET_DEST (pat));
-                 check_fpmode_conflict = 1;
-               }
-           }
+  /* We can only shift by constants <= 63. */
+  if (GET_CODE (operands[2]) == CONST_INT)
+    operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
 
-         slot = 4;
-         while(--slot >= 0)
-           {
-             rtx slot_insn = ultra_pipe.group[slot];
-             rtx slot_pat;
-
-             /* Already issued, bad dependency, or FPU
-                mode conflict.  */
-             if (slot_insn != 0
-                 && (slot_pat = PATTERN (slot_insn)) != 0
-                 && ((insn == slot_insn)
-                     || (check_depend == 1
-                         && GET_CODE (slot_insn) == INSN
-                         && GET_CODE (slot_pat) == SET
-                         && ((GET_CODE (SET_DEST (slot_pat)) == REG
-                              && GET_CODE (SET_SRC (pat)) == REG
-                              && REGNO (SET_DEST (slot_pat)) ==
-                                   REGNO (SET_SRC (pat)))
-                             || (GET_CODE (SET_DEST (slot_pat)) == SUBREG
-                                 && GET_CODE (SET_SRC (pat)) == SUBREG
-                                 && REGNO (SUBREG_REG (SET_DEST (slot_pat))) ==
-                                      REGNO (SUBREG_REG (SET_SRC (pat)))
-                                 && SUBREG_BYTE (SET_DEST (slot_pat)) ==
-                                      SUBREG_BYTE (SET_SRC (pat)))))
-                     || (check_fpmode_conflict == 1
-                         && GET_CODE (slot_insn) == INSN
-                         && GET_CODE (slot_pat) == SET
-                         && (GET_MODE (SET_DEST (slot_pat)) == SFmode
-                             || GET_MODE (SET_DEST (slot_pat)) == DFmode)
-                         && GET_MODE (SET_DEST (slot_pat)) != fpmode)))
-               goto next;
-           }
+  if (GET_CODE (operands[1]) == CONST_INT)
+    {
+      output_asm_insn ("mov\t%1, %3", operands);
+    }
+  else
+    {
+      output_asm_insn ("sllx\t%H1, 32, %3", operands);
+      if (sparc_check_64 (operands[1], insn) <= 0)
+       output_asm_insn ("srl\t%L1, 0, %L1", operands);
+      output_asm_insn ("or\t%L1, %3, %3", operands);
+    }
 
-         /* Check for peculiar result availability and dispatch
-            interference situations.  */
-         if (pat != 0
-             && ultra_cycles_elapsed > 0)
-           {
-             rtx link;
+  strcpy(asm_code, opcode);
 
-             for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
-               {
-                 rtx link_insn = XEXP (link, 0);
-                 if (GET_CODE (link_insn) == INSN
-                     && recog_memoized (link_insn) >= 0
-                     && (TMASK (get_attr_type (link_insn)) &
-                         (TMASK (TYPE_CMOVE) | TMASK (TYPE_FPCMOVE)))
-                     && ! ultra_cmove_results_ready_p (link_insn))
-                   goto next;
-               }
+  if (which_alternative != 2)
+    return strcat (asm_code, "\t%0, %2, %L0\n\tsrlx\t%L0, 32, %H0");
+  else
+    return strcat (asm_code, "\t%3, %2, %3\n\tsrlx\t%3, 32, %H0\n\tmov\t%3, %L0");
+}
+\f
+/* Output rtl to increment the profiler label LABELNO
+   for profiling a function entry.  */
 
-             if (check_fpmode_conflict
-                 && ultra_fpmode_conflict_exists (fpmode))
-               goto next;
-           }
+void
+sparc_profile_hook (int labelno)
+{
+  char buf[32];
+  rtx lab, fun;
 
-         return &list[i];
-       }
-    next:
-      ;
+  fun = gen_rtx_SYMBOL_REF (Pmode, MCOUNT_FUNCTION);
+  if (NO_PROFILE_COUNTERS)
+    {
+      emit_library_call (fun, LCT_NORMAL, VOIDmode, 0);
+    }
+  else
+    {
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
+      lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
+      emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode);
     }
-  return 0;
 }
-
+\f
+#ifdef OBJECT_FORMAT_ELF
 static void
-ultra_build_types_avail (ready, n_ready)
-  rtx *ready;
-  int n_ready;
+sparc_elf_asm_named_section (const char *name, unsigned int flags,
+                            tree decl)
 {
-  int i = n_ready - 1;
-
-  ultra_types_avail = 0;
-  while(i >= 0)
+  if (flags & SECTION_MERGE)
     {
-      rtx insn = ready[i];
+      /* entsize cannot be expressed in this section attributes
+        encoding style.  */
+      default_elf_asm_named_section (name, flags, decl);
+      return;
+    }
 
-      if (recog_memoized (insn) >= 0)
-       ultra_types_avail |= TMASK (get_attr_type (insn));
+  fprintf (asm_out_file, "\t.section\t\"%s\"", name);
 
-      i -= 1;
-    }
-}
+  if (!(flags & SECTION_DEBUG))
+    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);
 
-/* Place insn pointed to my IP into the pipeline.
-   Make element THIS of READY be that insn if it
-   is not already.  TYPE indicates the pipeline class
-   this insn falls into.  */
-static void
-ultra_schedule_insn (ip, ready, this, type)
-     rtx *ip;
-     rtx *ready;
-     int this;
-     enum ultra_code type;
-{
-  int pipe_slot;
-  char mask = ultra_pipe.free_slot_mask;
-  rtx temp;
+  /* ??? Handle SECTION_BSS.  */
 
-  /* Obtain free slot.  */
-  for (pipe_slot = 0; pipe_slot < 4; pipe_slot++)
-    if ((mask & (1 << pipe_slot)) != 0)
-      break;
-  if (pipe_slot == 4)
-    abort ();
+  fputc ('\n', asm_out_file);
+}
+#endif /* OBJECT_FORMAT_ELF */
 
-  /* In it goes, and it hasn't been committed yet.  */
-  ultra_pipe.group[pipe_slot] = *ip;
-  ultra_pipe.codes[pipe_slot] = type;
-  ultra_pipe.contents[type] = 1;
-  if (UMASK (type) &
-      (UMASK (IEUN) | UMASK (IEU0) | UMASK (IEU1)))
-    ultra_pipe.num_ieu_insns += 1;
+/* We do not allow indirect calls to be optimized into sibling calls.
 
-  ultra_pipe.free_slot_mask = (mask & ~(1 << pipe_slot));
-  ultra_pipe.group_size += 1;
-  ultra_pipe.commit[pipe_slot] = 0;
+   We cannot use sibling calls when delayed branches are disabled
+   because they will likely require the call delay slot to be filled.
 
-  /* Update ready list.  */
-  temp = *ip;
-  while (ip != &ready[this])
-    {
-      ip[0] = ip[1];
-      ++ip;
-    }
-  *ip = temp;
-}
+   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
+   function being called returns a structure.
 
-/* Advance to the next pipeline group.  */
-static void
-ultra_flush_pipeline ()
-{
-  ultra_cur_hist = (ultra_cur_hist + 1) & (ULTRA_NUM_HIST - 1);
-  ultra_cycles_elapsed += 1;
-  memset ((char *) &ultra_pipe, 0, sizeof ultra_pipe);
-  ultra_pipe.free_slot_mask = 0xf;
-}
+   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 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.
 
-/* Init our data structures for this current block.  */
-static void
-ultrasparc_sched_init ()
+   VxWorks PIC PLT entries require the global pointer to be initialized
+   on entry.  We therefore can't emit sibling calls to them.  */
+static bool
+sparc_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
-  memset ((char *) ultra_pipe_hist, 0, sizeof ultra_pipe_hist);
-  ultra_cur_hist = 0;
-  ultra_cycles_elapsed = 0;
-  ultra_pipe.free_slot_mask = 0xf;
+  return (decl
+         && flag_delayed_branch
+         && (TARGET_ARCH64 || ! cfun->returns_struct)
+         && !(TARGET_VXWORKS_RTP
+              && flag_pic
+              && !targetm.binds_local_p (decl)));
 }
+\f
+/* libfunc renaming.  */
+#include "config/gofast.h"
 
 static void
-sparc_sched_init (dump, sched_verbose, max_ready)
-     FILE *dump ATTRIBUTE_UNUSED;
-     int sched_verbose ATTRIBUTE_UNUSED;
-     int max_ready ATTRIBUTE_UNUSED;
-{
-  if (sparc_cpu == PROCESSOR_ULTRASPARC)
-    ultrasparc_sched_init ();
-}
-  
-/* INSN has been scheduled, update pipeline commit state
-   and return how many instructions are still to be
-   scheduled in this group.  */
-static int
-ultrasparc_variable_issue (insn)
-     rtx insn;
+sparc_init_libfuncs (void)
 {
-  struct ultrasparc_pipeline_state *up = &ultra_pipe;
-  int i, left_to_fire;
-
-  left_to_fire = 0;
-  for (i = 0; i < 4; i++)
+  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");
+      set_conv_libfunc (ufloat_optab, TFmode, SImode, "_Q_utoq");
+
+      if (DITF_CONVERSION_LIBFUNCS)
+       {
+         set_conv_libfunc (sfix_optab,   DImode, TFmode, "_Q_qtoll");
+         set_conv_libfunc (ufix_optab,   DImode, TFmode, "_Q_qtoull");
+         set_conv_libfunc (sfloat_optab, TFmode, DImode, "_Q_lltoq");
+         set_conv_libfunc (ufloat_optab, TFmode, DImode, "_Q_ulltoq");
+       }
+
+      if (SUN_CONVERSION_LIBFUNCS)
+       {
+         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)
     {
-      if (up->group[i] == 0)
-       continue;
+      /* 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);
+
+      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");
+       }
 
-      if (up->group[i] == insn)
+      if (SUN_CONVERSION_LIBFUNCS)
        {
-         up->commit[i] = 1;
+         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");
        }
-      else if (! up->commit[i])
-       left_to_fire++;
     }
 
-  return left_to_fire;
+  gofast_maybe_init_libfuncs ();
 }
+\f
+#define def_builtin(NAME, CODE, TYPE) \
+  add_builtin_function((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL, \
+                       NULL_TREE)
 
-static int
-sparc_variable_issue (dump, sched_verbose, insn, cim)
-     FILE *dump ATTRIBUTE_UNUSED;
-     int sched_verbose ATTRIBUTE_UNUSED;
-     rtx insn;
-     int cim;
-{
-  if (sparc_cpu == PROCESSOR_ULTRASPARC)
-    return ultrasparc_variable_issue (insn);
-  else
-    return cim - 1;
-}
+/* Implement the TARGET_INIT_BUILTINS target hook.
+   Create builtin functions for special SPARC instructions.  */
 
-/* In actual_hazard_this_instance, we may have yanked some
-   instructions from the ready list due to conflict cost
-   adjustments.  If so, and such an insn was in our pipeline
-   group, remove it and update state.  */
 static void
-ultra_rescan_pipeline_state (ready, n_ready)
-     rtx *ready;
-     int n_ready;
+sparc_init_builtins (void)
 {
-  struct ultrasparc_pipeline_state *up = &ultra_pipe;
-  int i;
+  if (TARGET_VIS)
+    sparc_vis_init_builtins ();
+}
 
-  for (i = 0; i < 4; i++)
-    {
-      rtx insn = up->group[i];
-      int j;
+/* Create builtin functions for VIS 1.0 instructions.  */
 
-      if (! insn)
-       continue;
+static void
+sparc_vis_init_builtins (void)
+{
+  tree v4qi = build_vector_type (unsigned_intQI_type_node, 4);
+  tree v8qi = build_vector_type (unsigned_intQI_type_node, 8);
+  tree v4hi = build_vector_type (intHI_type_node, 4);
+  tree v2hi = build_vector_type (intHI_type_node, 2);
+  tree v2si = build_vector_type (intSI_type_node, 2);
+
+  tree v4qi_ftype_v4hi = build_function_type_list (v4qi, v4hi, 0);
+  tree v8qi_ftype_v2si_v8qi = build_function_type_list (v8qi, v2si, v8qi, 0);
+  tree v2hi_ftype_v2si = build_function_type_list (v2hi, v2si, 0);
+  tree v4hi_ftype_v4qi = build_function_type_list (v4hi, v4qi, 0);
+  tree v8qi_ftype_v4qi_v4qi = build_function_type_list (v8qi, v4qi, v4qi, 0);
+  tree v4hi_ftype_v4qi_v4hi = build_function_type_list (v4hi, v4qi, v4hi, 0);
+  tree v4hi_ftype_v4qi_v2hi = build_function_type_list (v4hi, v4qi, v2hi, 0);
+  tree v2si_ftype_v4qi_v2hi = build_function_type_list (v2si, v4qi, v2hi, 0);
+  tree v4hi_ftype_v8qi_v4hi = build_function_type_list (v4hi, v8qi, v4hi, 0);
+  tree v4hi_ftype_v4hi_v4hi = build_function_type_list (v4hi, v4hi, v4hi, 0);
+  tree v2si_ftype_v2si_v2si = build_function_type_list (v2si, v2si, v2si, 0);
+  tree v8qi_ftype_v8qi_v8qi = build_function_type_list (v8qi, v8qi, v8qi, 0);
+  tree di_ftype_v8qi_v8qi_di = build_function_type_list (intDI_type_node,
+                                                        v8qi, v8qi,
+                                                        intDI_type_node, 0);
+  tree di_ftype_di_di = build_function_type_list (intDI_type_node,
+                                                 intDI_type_node,
+                                                 intDI_type_node, 0);
+  tree ptr_ftype_ptr_si = build_function_type_list (ptr_type_node,
+                                                   ptr_type_node,
+                                                   intSI_type_node, 0);
+  tree ptr_ftype_ptr_di = build_function_type_list (ptr_type_node,
+                                                   ptr_type_node,
+                                                   intDI_type_node, 0);
+
+  /* Packing and expanding vectors.  */
+  def_builtin ("__builtin_vis_fpack16", CODE_FOR_fpack16_vis, v4qi_ftype_v4hi);
+  def_builtin ("__builtin_vis_fpack32", CODE_FOR_fpack32_vis,
+              v8qi_ftype_v2si_v8qi);
+  def_builtin ("__builtin_vis_fpackfix", CODE_FOR_fpackfix_vis,
+              v2hi_ftype_v2si);
+  def_builtin ("__builtin_vis_fexpand", CODE_FOR_fexpand_vis, v4hi_ftype_v4qi);
+  def_builtin ("__builtin_vis_fpmerge", CODE_FOR_fpmerge_vis,
+              v8qi_ftype_v4qi_v4qi);
+
+  /* Multiplications.  */
+  def_builtin ("__builtin_vis_fmul8x16", CODE_FOR_fmul8x16_vis,
+              v4hi_ftype_v4qi_v4hi);
+  def_builtin ("__builtin_vis_fmul8x16au", CODE_FOR_fmul8x16au_vis,
+              v4hi_ftype_v4qi_v2hi);
+  def_builtin ("__builtin_vis_fmul8x16al", CODE_FOR_fmul8x16al_vis,
+              v4hi_ftype_v4qi_v2hi);
+  def_builtin ("__builtin_vis_fmul8sux16", CODE_FOR_fmul8sux16_vis,
+              v4hi_ftype_v8qi_v4hi);
+  def_builtin ("__builtin_vis_fmul8ulx16", CODE_FOR_fmul8ulx16_vis,
+              v4hi_ftype_v8qi_v4hi);
+  def_builtin ("__builtin_vis_fmuld8sux16", CODE_FOR_fmuld8sux16_vis,
+              v2si_ftype_v4qi_v2hi);
+  def_builtin ("__builtin_vis_fmuld8ulx16", CODE_FOR_fmuld8ulx16_vis,
+              v2si_ftype_v4qi_v2hi);
+
+  /* Data aligning.  */
+  def_builtin ("__builtin_vis_faligndatav4hi", CODE_FOR_faligndatav4hi_vis,
+              v4hi_ftype_v4hi_v4hi);
+  def_builtin ("__builtin_vis_faligndatav8qi", CODE_FOR_faligndatav8qi_vis,
+              v8qi_ftype_v8qi_v8qi);
+  def_builtin ("__builtin_vis_faligndatav2si", CODE_FOR_faligndatav2si_vis,
+              v2si_ftype_v2si_v2si);
+  def_builtin ("__builtin_vis_faligndatadi", CODE_FOR_faligndatadi_vis,
+               di_ftype_di_di);
+  if (TARGET_ARCH64)
+    def_builtin ("__builtin_vis_alignaddr", CODE_FOR_alignaddrdi_vis,
+                ptr_ftype_ptr_di);
+  else
+    def_builtin ("__builtin_vis_alignaddr", CODE_FOR_alignaddrsi_vis,
+                ptr_ftype_ptr_si);
 
-      /* If it has been committed, then it was removed from
-        the ready list because it was actually scheduled,
-        and that is not the case we are searching for here.  */
-      if (up->commit[i] != 0)
-       continue;
+  /* Pixel distance.  */
+  def_builtin ("__builtin_vis_pdist", CODE_FOR_pdist_vis,
+              di_ftype_v8qi_v8qi_di);
+}
 
-      for (j = n_ready - 1; j >= 0; j--)
-       if (ready[j] == insn)
-         break;
+/* Handle TARGET_EXPAND_BUILTIN target hook.
+   Expand builtin functions for sparc intrinsics.  */
 
-      /* If we didn't find it, toss it.  */
-      if (j < 0)
-       {
-         enum ultra_code ucode = up->codes[i];
+static rtx
+sparc_expand_builtin (tree exp, rtx target,
+                     rtx subtarget ATTRIBUTE_UNUSED,
+                     enum machine_mode tmode ATTRIBUTE_UNUSED,
+                     int ignore ATTRIBUTE_UNUSED)
+{
+  tree arg;
+  call_expr_arg_iterator iter;
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+  unsigned int icode = DECL_FUNCTION_CODE (fndecl);
+  rtx pat, op[4];
+  enum machine_mode mode[4];
+  int arg_count = 0;
+
+  mode[0] = insn_data[icode].operand[0].mode;
+  if (!target
+      || GET_MODE (target) != mode[0]
+      || ! (*insn_data[icode].operand[0].predicate) (target, mode[0]))
+    op[0] = gen_reg_rtx (mode[0]);
+  else
+    op[0] = target;
 
-         up->group[i] = 0;
-         up->codes[i] = NONE;
-         up->contents[ucode] = 0;
-         if (UMASK (ucode) &
-             (UMASK (IEUN) | UMASK (IEU0) | UMASK (IEU1)))
-           up->num_ieu_insns -= 1;
+  FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
+    {
+      arg_count++;
+      mode[arg_count] = insn_data[icode].operand[arg_count].mode;
+      op[arg_count] = expand_normal (arg);
 
-         up->free_slot_mask |= (1 << i);
-         up->group_size -= 1;
-         up->commit[i] = 0;
-       }
+      if (! (*insn_data[icode].operand[arg_count].predicate) (op[arg_count],
+                                                             mode[arg_count]))
+       op[arg_count] = copy_to_mode_reg (mode[arg_count], op[arg_count]);
+    }
+
+  switch (arg_count)
+    {
+    case 1:
+      pat = GEN_FCN (icode) (op[0], op[1]);
+      break;
+    case 2:
+      pat = GEN_FCN (icode) (op[0], op[1], op[2]);
+      break;
+    case 3:
+      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
+      break;
+    default:
+      gcc_unreachable ();
     }
+
+  if (!pat)
+    return NULL_RTX;
+
+  emit_insn (pat);
+
+  return op[0];
 }
 
-static void
-ultrasparc_sched_reorder (dump, sched_verbose, ready, n_ready)
-     FILE *dump;
-     int sched_verbose;
-     rtx *ready;
-     int n_ready;
+static int
+sparc_vis_mul8x16 (int e8, int e16)
 {
-  struct ultrasparc_pipeline_state *up = &ultra_pipe;
-  int i, this_insn;
+  return (e8 * e16 + 128) / 256;
+}
 
-  if (sched_verbose)
-    {
-      int n;
+/* Multiply the vector elements in ELTS0 to the elements in ELTS1 as specified
+   by FNCODE.  All of the elements in ELTS0 and ELTS1 lists must be integer
+   constants.  A tree list with the results of the multiplications is returned,
+   and each element in the list is of INNER_TYPE.  */
 
-      fprintf (dump, "\n;;\tUltraSPARC Looking at [");
-      for (n = n_ready - 1; n >= 0; n--)
-       {
-         rtx insn = ready[n];
-         enum ultra_code ucode;
+static tree
+sparc_handle_vis_mul8x16 (int fncode, tree inner_type, tree elts0, tree elts1)
+{
+  tree n_elts = NULL_TREE;
+  int scale;
 
-         if (recog_memoized (insn) < 0)
-           continue;
-         ucode = ultra_code_from_mask (TMASK (get_attr_type (insn)));
-         if (n != 0)
-           fprintf (dump, "%s(%d) ",
-                    ultra_code_names[ucode],
-                    INSN_UID (insn));
-         else
-           fprintf (dump, "%s(%d)",
-                    ultra_code_names[ucode],
-                    INSN_UID (insn));
+  switch (fncode)
+    {
+    case CODE_FOR_fmul8x16_vis:
+      for (; elts0 && elts1;
+          elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
+       {
+         int val
+           = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+                                TREE_INT_CST_LOW (TREE_VALUE (elts1)));
+         n_elts = tree_cons (NULL_TREE,
+                             build_int_cst (inner_type, val),
+                             n_elts);
        }
-      fprintf (dump, "]\n");
-    }
+      break;
 
-  this_insn = n_ready - 1;
+    case CODE_FOR_fmul8x16au_vis:
+      scale = TREE_INT_CST_LOW (TREE_VALUE (elts1));
 
-  /* Skip over junk we don't understand.  */
-  while ((this_insn >= 0)
-        && recog_memoized (ready[this_insn]) < 0)
-    this_insn--;
+      for (; elts0; elts0 = TREE_CHAIN (elts0))
+       {
+         int val
+           = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+                                scale);
+         n_elts = tree_cons (NULL_TREE,
+                             build_int_cst (inner_type, val),
+                             n_elts);
+       }
+      break;
 
-  ultra_build_types_avail (ready, this_insn + 1);
+    case CODE_FOR_fmul8x16al_vis:
+      scale = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (elts1)));
 
-  while (this_insn >= 0) {
-    int old_group_size = up->group_size;
+      for (; elts0; elts0 = TREE_CHAIN (elts0))
+       {
+         int val
+           = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+                                scale);
+         n_elts = tree_cons (NULL_TREE,
+                             build_int_cst (inner_type, val),
+                             n_elts);
+       }
+      break;
 
-    if (up->group_size != 0)
-      {
-       int num_committed;
-
-       num_committed = (up->commit[0] + up->commit[1] +
-                        up->commit[2] + up->commit[3]);
-       /* If nothing has been commited from our group, or all of
-          them have.  Clear out the (current cycle's) pipeline
-          state and start afresh.  */
-       if (num_committed == 0
-           || num_committed == up->group_size)
-         {
-           ultra_flush_pipeline ();
-           up = &ultra_pipe;
-           old_group_size = 0;
-         }
-       else
-         {
-           /* OK, some ready list insns got requeued and thus removed
-              from the ready list.  Account for this fact.  */
-           ultra_rescan_pipeline_state (ready, n_ready);
-
-           /* Something "changed", make this look like a newly
-              formed group so the code at the end of the loop
-              knows that progress was in fact made.  */
-           if (up->group_size != old_group_size)
-             old_group_size = 0;
-         }
-      }
+    default:
+      gcc_unreachable ();
+    }
 
-    if (up->group_size == 0)
-      {
-       /* If the pipeline is (still) empty and we have any single
-          group insns, get them out now as this is a good time.  */
-       rtx *ip = ultra_find_type ((TMASK (TYPE_RETURN) | TMASK (TYPE_IDIV) |
-                                   TMASK (TYPE_IMUL) | TMASK (TYPE_CMOVE) |
-                                   TMASK (TYPE_MULTI) | TMASK (TYPE_MISC)),
-                                  ready, this_insn);
-       if (ip)
-         {
-           ultra_schedule_insn (ip, ready, this_insn, SINGLE);
-           break;
-         }
+  return nreverse (n_elts);
 
-       /* If we are not in the process of emptying out the pipe, try to
-          obtain an instruction which must be the first in it's group.  */
-       ip = ultra_find_type ((TMASK (TYPE_CALL) |
-                              TMASK (TYPE_SIBCALL) |
-                              TMASK (TYPE_CALL_NO_DELAY_SLOT) |
-                              TMASK (TYPE_UNCOND_BRANCH)),
-                             ready, this_insn);
-       if (ip)
-         {
-           ultra_schedule_insn (ip, ready, this_insn, IEU1);
-           this_insn--;
-         }
-       else if ((ip = ultra_find_type ((TMASK (TYPE_FPDIVS) |
-                                        TMASK (TYPE_FPDIVD) |
-                                        TMASK (TYPE_FPSQRTS) |
-                                        TMASK (TYPE_FPSQRTD)),
-                                       ready, this_insn)) != 0)
-         {
-           ultra_schedule_insn (ip, ready, this_insn, FPM);
-           this_insn--;
-         }
-      }
+}
+/* Handle TARGET_FOLD_BUILTIN target hook.
+   Fold builtin functions for SPARC intrinsics.  If IGNORE is true the
+   result of the function call is ignored.  NULL_TREE is returned if the
+   function could not be folded.  */
 
-    /* Try to fill the integer pipeline.  First, look for an IEU0 specific
-       operation.  We can't do more IEU operations if the first 3 slots are
-       all full or we have dispatched two IEU insns already.  */
-    if ((up->free_slot_mask & 0x7) != 0
-       && up->num_ieu_insns < 2
-       && up->contents[IEU0] == 0
-       && up->contents[IEUN] == 0)
-      {
-       rtx *ip = ultra_find_type (TMASK(TYPE_SHIFT), ready, this_insn);
-       if (ip)
-         {
-           ultra_schedule_insn (ip, ready, this_insn, IEU0);
-           this_insn--;
-         }
-      }
+static tree
+sparc_fold_builtin (tree fndecl, tree arglist, bool ignore)
+{
+  tree arg0, arg1, arg2;
+  tree rtype = TREE_TYPE (TREE_TYPE (fndecl));
 
-    /* If we can, try to find an IEU1 specific or an unnamed
-       IEU instruction.  */
-    if ((up->free_slot_mask & 0x7) != 0
-       && up->num_ieu_insns < 2)
-      {
-       rtx *ip = ultra_find_type ((TMASK (TYPE_IALU) |
-                                   (up->contents[IEU1] == 0 ? TMASK (TYPE_COMPARE) : 0)),
-                                  ready, this_insn);
-       if (ip)
-         {
-           rtx insn = *ip;
+  if (ignore
+      && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrsi_vis
+      && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrdi_vis)
+    return fold_convert (rtype, integer_zero_node);
 
-           ultra_schedule_insn (ip, ready, this_insn,
-                                (!up->contents[IEU1]
-                                 && get_attr_type (insn) == TYPE_COMPARE)
-                                ? IEU1 : IEUN);
-           this_insn--;
-         }
-      }
+  switch (DECL_FUNCTION_CODE (fndecl))
+    {
+    case CODE_FOR_fexpand_vis:
+      arg0 = TREE_VALUE (arglist);
+      STRIP_NOPS (arg0);
 
-    /* If only one IEU insn has been found, try to find another unnamed
-       IEU operation or an IEU1 specific one.  */
-    if ((up->free_slot_mask & 0x7) != 0
-       && up->num_ieu_insns < 2)
-      {
-       rtx *ip;
-       int tmask = TMASK (TYPE_IALU);
+      if (TREE_CODE (arg0) == VECTOR_CST)
+       {
+         tree inner_type = TREE_TYPE (rtype);
+         tree elts = TREE_VECTOR_CST_ELTS (arg0);
+         tree n_elts = NULL_TREE;
 
-       if (!up->contents[IEU1])
-         tmask |= TMASK (TYPE_COMPARE);
-       ip = ultra_find_type (tmask, ready, this_insn);
-       if (ip)
-         {
-           rtx insn = *ip;
+         for (; elts; elts = TREE_CHAIN (elts))
+           {
+             unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (elts)) << 4;
+             n_elts = tree_cons (NULL_TREE,
+                                 build_int_cst (inner_type, val),
+                                 n_elts);
+           }
+         return build_vector (rtype, nreverse (n_elts));
+       }
+      break;
 
-           ultra_schedule_insn (ip, ready, this_insn,
-                                (!up->contents[IEU1]
-                                 && get_attr_type (insn) == TYPE_COMPARE)
-                                ? IEU1 : IEUN);
-           this_insn--;
-         }
-      }
+    case CODE_FOR_fmul8x16_vis:
+    case CODE_FOR_fmul8x16au_vis:
+    case CODE_FOR_fmul8x16al_vis:
+      arg0 = TREE_VALUE (arglist);
+      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
 
-    /* Try for a load or store, but such an insn can only be issued
-       if it is within' one of the first 3 slots.  */
-    if ((up->free_slot_mask & 0x7) != 0
-        && up->contents[LSU] == 0)
-      {
-       rtx *ip = ultra_find_type ((TMASK (TYPE_LOAD) | TMASK (TYPE_SLOAD) |
-                                  TMASK (TYPE_STORE) | TMASK (TYPE_FPLOAD) |
-                                  TMASK (TYPE_FPSTORE)), ready, this_insn);
-       if (ip)
-         {
-           ultra_schedule_insn (ip, ready, this_insn, LSU);
-           this_insn--;
-         }
-      }
+      if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
+       {
+         tree inner_type = TREE_TYPE (rtype);
+         tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
+         tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
+         tree n_elts = sparc_handle_vis_mul8x16 (DECL_FUNCTION_CODE (fndecl),
+                                                 inner_type, elts0, elts1);
 
-    /* Now find FPU operations, first FPM class.  But not divisions or
-       square-roots because those will break the group up.  Unlike all
-       the previous types, these can go in any slot.  */
-    if (up->free_slot_mask != 0
-       && up->contents[FPM] == 0)
-      {
-       rtx *ip = ultra_find_type (TMASK (TYPE_FPMUL), ready, this_insn);
-       if (ip)
-         {
-           ultra_schedule_insn (ip, ready, this_insn, FPM);
-           this_insn--;
-         }
-      }
-    
-    /* Continue on with FPA class if we have not filled the group already.  */
-    if (up->free_slot_mask != 0
-       && up->contents[FPA] == 0)
-      {
-       rtx *ip = ultra_find_type ((TMASK (TYPE_FPMOVE) | TMASK (TYPE_FPCMOVE) |
-                                   TMASK (TYPE_FP) | TMASK (TYPE_FPCMP)),
-                                  ready, this_insn);
-       if (ip)
-         {
-           ultra_schedule_insn (ip, ready, this_insn, FPA);
-           this_insn--;
-         }
-      }
+         return build_vector (rtype, n_elts);
+       }
+      break;
 
-    /* Finally, maybe stick a branch in here.  */
-    if (up->free_slot_mask != 0
-       && up->contents[CTI] == 0)
-      {
-       rtx *ip = ultra_find_type (TMASK (TYPE_BRANCH), ready, this_insn);
+    case CODE_FOR_fpmerge_vis:
+      arg0 = TREE_VALUE (arglist);
+      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
 
-       /* Try to slip in a branch only if it is one of the
-          next 2 in the ready list.  */
-       if (ip && ((&ready[this_insn] - ip) < 2))
-         {
-           ultra_schedule_insn (ip, ready, this_insn, CTI);
-           this_insn--;
-         }
-      }
+      if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
+       {
+         tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
+         tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
+         tree n_elts = NULL_TREE;
 
-    up->group_size = 0;
-    for (i = 0; i < 4; i++)
-      if ((up->free_slot_mask & (1 << i)) == 0)
-       up->group_size++;
+         for (; elts0 && elts1;
+              elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
+           {
+             n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts0), n_elts);
+             n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts1), n_elts);
+           }
 
-    /* See if we made any progress...  */
-    if (old_group_size != up->group_size)
+         return build_vector (rtype, nreverse (n_elts));
+       }
       break;
 
-    /* Clean out the (current cycle's) pipeline state
-       and try once more.  If we placed no instructions
-       into the pipeline at all, it means a real hard
-       conflict exists with some earlier issued instruction
-       so we must advance to the next cycle to clear it up.  */
-    if (up->group_size == 0)
-      {
-       ultra_flush_pipeline ();
-       up = &ultra_pipe;
-      }
-    else
-      {
-       memset ((char *) &ultra_pipe, 0, sizeof ultra_pipe);
-       ultra_pipe.free_slot_mask = 0xf;
-      }
-  }
+    case CODE_FOR_pdist_vis:
+      arg0 = TREE_VALUE (arglist);
+      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
+      STRIP_NOPS (arg2);
+
+      if (TREE_CODE (arg0) == VECTOR_CST
+         && TREE_CODE (arg1) == VECTOR_CST
+         && TREE_CODE (arg2) == INTEGER_CST)
+       {
+         int overflow = 0;
+         unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (arg2);
+         HOST_WIDE_INT high = TREE_INT_CST_HIGH (arg2);
+         tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
+         tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
+
+         for (; elts0 && elts1;
+              elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
+           {
+             unsigned HOST_WIDE_INT
+               low0 = TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+               low1 = TREE_INT_CST_LOW (TREE_VALUE (elts1));
+             HOST_WIDE_INT high0 = TREE_INT_CST_HIGH (TREE_VALUE (elts0));
+             HOST_WIDE_INT high1 = TREE_INT_CST_HIGH (TREE_VALUE (elts1));
 
-  if (sched_verbose)
-    {
-      int n, gsize;
+             unsigned HOST_WIDE_INT l;
+             HOST_WIDE_INT h;
 
-      fprintf (dump, ";;\tUltraSPARC Launched   [");
-      gsize = up->group_size;
-      for (n = 0; n < 4; n++)
-       {
-         rtx insn = up->group[n];
+             overflow |= neg_double (low1, high1, &l, &h);
+             overflow |= add_double (low0, high0, l, h, &l, &h);
+             if (h < 0)
+               overflow |= neg_double (l, h, &l, &h);
 
-         if (! insn)
-           continue;
+             overflow |= add_double (low, high, l, h, &low, &high);
+           }
 
-         gsize -= 1;
-         if (gsize != 0)
-           fprintf (dump, "%s(%d) ",
-                    ultra_code_names[up->codes[n]],
-                    INSN_UID (insn));
-         else
-           fprintf (dump, "%s(%d)",
-                    ultra_code_names[up->codes[n]],
-                    INSN_UID (insn));
-       }
-      fprintf (dump, "]\n");
-    }
-}
+         gcc_assert (overflow == 0);
 
-static int
-sparc_sched_reorder (dump, sched_verbose, ready, n_readyp, clock)
-     FILE *dump;
-     int sched_verbose;
-     rtx *ready;
-     int *n_readyp;
-     int clock ATTRIBUTE_UNUSED;
-{
-  if (sparc_cpu == PROCESSOR_ULTRASPARC)
-    ultrasparc_sched_reorder (dump, sched_verbose, ready, *n_readyp);
-  return sparc_issue_rate ();
-}
+         return build_int_cst_wide (rtype, low, high);
+       }
 
-static int                                                           
-sparc_issue_rate ()
-{
-  switch (sparc_cpu)
-    {
-    default:                                 
-      return 1;                                                    
-    case PROCESSOR_V9:                                                
-      /* Assume V9 processors are capable of at least dual-issue.  */
-      return 2;
-    case PROCESSOR_SUPERSPARC:                                        
-      return 3;                                                      
-    case PROCESSOR_HYPERSPARC:
-    case PROCESSOR_SPARCLITE86X:
-      return 2;
-    case PROCESSOR_ULTRASPARC:                                            
-      return 4;                                                    
+    default:
+      break;
     }
+
+  return NULL_TREE;
 }
+\f
+/* ??? This duplicates information provided to the compiler by the
+   ??? scheduler description.  Some day, teach genautomata to output
+   ??? the latencies and then CSE will just use that.  */
 
-static int
-set_extends (insn)
-     rtx insn;
+static bool
+sparc_rtx_costs (rtx x, int code, int outer_code, int *total,
+                bool speed ATTRIBUTE_UNUSED)
 {
-  register rtx pat = PATTERN (insn);
+  enum machine_mode mode = GET_MODE (x);
+  bool float_mode_p = FLOAT_MODE_P (mode);
 
-  switch (GET_CODE (SET_SRC (pat)))
+  switch (code)
     {
-      /* Load and some shift instructions zero extend.  */
-    case MEM:
-    case ZERO_EXTEND:
-      /* sethi clears the high bits */
+    case CONST_INT:
+      if (INTVAL (x) < 0x1000 && INTVAL (x) >= -0x1000)
+       {
+         *total = 0;
+         return true;
+       }
+      /* FALLTHRU */
+
     case HIGH:
-      /* LO_SUM is used with sethi.  sethi cleared the high
-        bits and the values used with lo_sum are positive */
-    case LO_SUM:
-      /* Store flag stores 0 or 1 */
-    case LT: case LTU:
-    case GT: case GTU:
-    case LE: case LEU:
-    case GE: case GEU:
-    case EQ:
-    case NE:
-      return 1;
-    case AND:
-      {
-       rtx op0 = XEXP (SET_SRC (pat), 0);
-       rtx op1 = XEXP (SET_SRC (pat), 1);
-       if (GET_CODE (op1) == CONST_INT)
-         return INTVAL (op1) >= 0;
-       if (GET_CODE (op0) != REG)
-         return 0;
-       if (sparc_check_64 (op0, insn) == 1)
-         return 1;
-       return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
-      }
-    case IOR:
-    case XOR:
-      {
-       rtx op0 = XEXP (SET_SRC (pat), 0);
-       rtx op1 = XEXP (SET_SRC (pat), 1);
-       if (GET_CODE (op0) != REG || sparc_check_64 (op0, insn) <= 0)
-         return 0;
-       if (GET_CODE (op1) == CONST_INT)
-         return INTVAL (op1) >= 0;
-       return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
-      }
-    case LSHIFTRT:
-      return GET_MODE (SET_SRC (pat)) == SImode;
-      /* Positive integers leave the high bits zero.  */
+      *total = 2;
+      return true;
+
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+      *total = 4;
+      return true;
+
     case CONST_DOUBLE:
-      return ! (CONST_DOUBLE_LOW (SET_SRC (pat)) & 0x80000000);
-    case CONST_INT:
-      return ! (INTVAL (SET_SRC (pat)) & 0x80000000);
-    case ASHIFTRT:
-    case SIGN_EXTEND:
-      return - (GET_MODE (SET_SRC (pat)) == SImode);
-    case REG:
-      return sparc_check_64 (SET_SRC (pat), insn);
-    default:
-      return 0;
-    }
-}
+      if (GET_MODE (x) == VOIDmode
+         && ((CONST_DOUBLE_HIGH (x) == 0
+              && CONST_DOUBLE_LOW (x) < 0x1000)
+             || (CONST_DOUBLE_HIGH (x) == -1
+                 && CONST_DOUBLE_LOW (x) < 0
+                 && CONST_DOUBLE_LOW (x) >= -0x1000)))
+       *total = 0;
+      else
+       *total = 8;
+      return true;
 
-/* We _ought_ to have only one kind per function, but...  */
-static rtx sparc_addr_diff_list;
-static rtx sparc_addr_list;
+    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)
+       {
+         *total = sparc_costs->int_zload - COSTS_N_INSNS (1);
+       }
+      else if (outer_code == SIGN_EXTEND)
+       {
+         *total = sparc_costs->int_sload - COSTS_N_INSNS (1);
+       }
+      else if (float_mode_p)
+       {
+         *total = sparc_costs->float_load;
+       }
+      else
+       {
+         *total = sparc_costs->int_load;
+       }
 
-void
-sparc_defer_case_vector (lab, vec, diff)
-     rtx lab, vec;
-     int diff;
-{
-  vec = gen_rtx_EXPR_LIST (VOIDmode, lab, vec);
-  if (diff)
-    sparc_addr_diff_list
-      = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_diff_list);
-  else
-    sparc_addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_list);
-}
+      return true;
 
-static void 
-sparc_output_addr_vec (vec)
-     rtx vec;
-{
-  rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
-  int idx, vlen = XVECLEN (body, 0);
+    case PLUS:
+    case MINUS:
+      if (float_mode_p)
+       *total = sparc_costs->float_plusminus;
+      else
+       *total = COSTS_N_INSNS (1);
+      return false;
 
-#ifdef ASM_OUTPUT_ADDR_VEC_START  
-  ASM_OUTPUT_ADDR_VEC_START (asm_out_file);
-#endif
+    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;
 
-#ifdef ASM_OUTPUT_CASE_LABEL
-  ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab),
-                        NEXT_INSN (lab));
-#else
-  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab));
-#endif
+         bit_cost = 0;
+         if (sparc_costs->int_mul_bit_factor)
+           {
+             int nbits;
 
-  for (idx = 0; idx < vlen; idx++)
-    {
-      ASM_OUTPUT_ADDR_VEC_ELT
-       (asm_out_file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
-    }
-    
-#ifdef ASM_OUTPUT_ADDR_VEC_END
-  ASM_OUTPUT_ADDR_VEC_END (asm_out_file);
-#endif
-}
+             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)) == VOIDmode)
+               {
+                 rtx x1 = XEXP (x, 1);
+                 unsigned HOST_WIDE_INT value1 = CONST_DOUBLE_LOW (x1);
+                 unsigned HOST_WIDE_INT value2 = CONST_DOUBLE_HIGH (x1);
+
+                 for (nbits = 0; value1 != 0; value1 &= value1 - 1)
+                   nbits++;
+                 for (; value2 != 0; value2 &= value2 - 1)
+                   nbits++;
+               }
+             else
+               nbits = 7;
 
-static void 
-sparc_output_addr_diff_vec (vec)
-     rtx vec;
-{
-  rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
-  rtx base = XEXP (XEXP (body, 0), 0);
-  int idx, vlen = XVECLEN (body, 1);
+             if (nbits < 3)
+               nbits = 3;
+             bit_cost = (nbits - 3) / sparc_costs->int_mul_bit_factor;
+             bit_cost = COSTS_N_INSNS (bit_cost);
+           }
 
-#ifdef ASM_OUTPUT_ADDR_VEC_START  
-  ASM_OUTPUT_ADDR_VEC_START (asm_out_file);
-#endif
+         if (mode == DImode)
+           *total = sparc_costs->int_mulX + bit_cost;
+         else
+           *total = sparc_costs->int_mul + bit_cost;
+       }
+      return false;
 
-#ifdef ASM_OUTPUT_CASE_LABEL
-  ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab),
-                        NEXT_INSN (lab));
-#else
-  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab));
-#endif
+    case ASHIFT:
+    case ASHIFTRT:
+    case LSHIFTRT:
+      *total = COSTS_N_INSNS (1) + sparc_costs->shift_penalty;
+      return false;
+
+    case DIV:
+    case UDIV:
+    case MOD:
+    case UMOD:
+      if (float_mode_p)
+       {
+         if (mode == DFmode)
+           *total = sparc_costs->float_div_df;
+         else
+           *total = sparc_costs->float_div_sf;
+       }
+      else
+       {
+         if (mode == DImode)
+           *total = sparc_costs->int_divX;
+         else
+           *total = sparc_costs->int_div;
+       }
+      return false;
+
+    case NEG:
+      if (! float_mode_p)
+       {
+         *total = COSTS_N_INSNS (1);
+         return false;
+       }
+      /* FALLTHRU */
+
+    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 SQRT:
+      if (mode == DFmode)
+       *total = sparc_costs->float_sqrt_df;
+      else
+       *total = sparc_costs->float_sqrt_sf;
+      return false;
+
+    case COMPARE:
+      if (float_mode_p)
+       *total = sparc_costs->float_cmp;
+      else
+       *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;
+
+    case IOR:
+      /* Handle the NAND vector patterns.  */
+      if (sparc_vector_mode_supported_p (GET_MODE (x))
+         && GET_CODE (XEXP (x, 0)) == NOT
+         && GET_CODE (XEXP (x, 1)) == NOT)
+       {
+         *total = COSTS_N_INSNS (1);
+         return true;
+       }
+      else
+        return false;
 
-  for (idx = 0; idx < vlen; idx++)
-    {
-      ASM_OUTPUT_ADDR_DIFF_ELT
-        (asm_out_file,
-         body,
-         CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
-         CODE_LABEL_NUMBER (base));
+    default:
+      return false;
     }
-    
-#ifdef ASM_OUTPUT_ADDR_VEC_END
-  ASM_OUTPUT_ADDR_VEC_END (asm_out_file);
-#endif
 }
 
+/* Emit the sequence of insns SEQ while preserving the registers REG and REG2.
+   This is achieved by means of a manual dynamic stack space allocation in
+   the current frame.  We make the assumption that SEQ doesn't contain any
+   function calls, with the possible exception of calls to the PIC helper.  */
+
+static void
+emit_and_preserve (rtx seq, rtx reg, rtx reg2)
+{
+  /* We must preserve the lowest 16 words for the register save area.  */
+  HOST_WIDE_INT offset = 16*UNITS_PER_WORD;
+  /* We really need only 2 words of fresh stack space.  */
+  HOST_WIDE_INT size = SPARC_STACK_ALIGN (offset + 2*UNITS_PER_WORD);
+
+  rtx slot
+    = gen_rtx_MEM (word_mode, plus_constant (stack_pointer_rtx,
+                                            SPARC_STACK_BIAS + offset));
+
+  emit_insn (gen_stack_pointer_dec (GEN_INT (size)));
+  emit_insn (gen_rtx_SET (VOIDmode, slot, reg));
+  if (reg2)
+    emit_insn (gen_rtx_SET (VOIDmode,
+                           adjust_address (slot, word_mode, UNITS_PER_WORD),
+                           reg2));
+  emit_insn (seq);
+  if (reg2)
+    emit_insn (gen_rtx_SET (VOIDmode,
+                           reg2,
+                           adjust_address (slot, word_mode, UNITS_PER_WORD)));
+  emit_insn (gen_rtx_SET (VOIDmode, reg, slot));
+  emit_insn (gen_stack_pointer_inc (GEN_INT (size)));
+}
+
+/* Output the assembler code for a thunk function.  THUNK_DECL is the
+   declaration for the thunk function itself, FUNCTION is the decl for
+   the target function.  DELTA is an immediate constant offset to be
+   added to THIS.  If VCALL_OFFSET is nonzero, the word at address
+   (*THIS + VCALL_OFFSET) should be additionally added to THIS.  */
+
 static void
-sparc_output_deferred_case_vectors ()
+sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
+                      HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
+                      tree function)
 {
-  rtx t;
-  int align;
+  rtx this_rtx, insn, funexp;
+  unsigned int int_arg_first;
 
-  if (sparc_addr_list == NULL_RTX
-      && sparc_addr_diff_list == NULL_RTX)
-    return;
+  reload_completed = 1;
+  epilogue_completed = 1;
 
-  /* Align to cache line in the function's code section.  */
-  function_section (current_function_decl);
+  emit_note (NOTE_INSN_PROLOGUE_END);
 
-  align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
-  if (align > 0)
-    ASM_OUTPUT_ALIGN (asm_out_file, align);
-  
-  for (t = sparc_addr_list; t ; t = XEXP (t, 1))
-    sparc_output_addr_vec (XEXP (t, 0));
-  for (t = sparc_addr_diff_list; t ; t = XEXP (t, 1))
-    sparc_output_addr_diff_vec (XEXP (t, 0));
+  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.  */
+      sparc_leaf_function_p = current_function_uses_only_leaf_regs = 1;
 
-  sparc_addr_list = sparc_addr_diff_list = NULL_RTX;
-}
+      /* 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.  */
+      sparc_leaf_function_p = current_function_uses_only_leaf_regs = 0;
 
-/* Return 0 if the high 32 bits of X (the low word of X, if DImode) are
-   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;
-{
-  /* 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
-     the single set and return the correct value or fail to recognize
-     it and return 0.  */
-  int set_once = 0;
-  rtx y = x;
+      /* We really are in a leaf function.  */
+      int_arg_first = SPARC_OUTGOING_INT_ARG_FIRST;
+    }
 
-  if (GET_CODE (x) != REG)
-    abort ();
+  /* Find the "this" pointer.  Normally in %o0, but in ARCH64 if the function
+     returns a structure, the structure return pointer is there instead.  */
+  if (TARGET_ARCH64 && aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
+    this_rtx = gen_rtx_REG (Pmode, int_arg_first + 1);
+  else
+    this_rtx = gen_rtx_REG (Pmode, int_arg_first);
 
-  if (GET_MODE (x) == DImode)
-    y = gen_rtx_REG (SImode, REGNO (x) + WORDS_BIG_ENDIAN);
+  /* Add DELTA.  When possible use a plain add, otherwise load it into
+     a register first.  */
+  if (delta)
+    {
+      rtx delta_rtx = GEN_INT (delta);
 
-  if (flag_expensive_optimizations
-      && REG_N_SETS (REGNO (y)) == 1)
-    set_once = 1;
+      if (! SPARC_SIMM13_P (delta))
+       {
+         rtx scratch = gen_rtx_REG (Pmode, 1);
+         emit_move_insn (scratch, delta_rtx);
+         delta_rtx = scratch;
+       }
 
-  if (insn == 0)
-    {
-      if (set_once)
-       insn = get_last_insn_anywhere ();
-      else
-       return 0;
+      /* THIS_RTX += DELTA.  */
+      emit_insn (gen_add2_insn (this_rtx, delta_rtx));
     }
 
-  while ((insn = PREV_INSN (insn)))
+  /* Add the word at address (*THIS_RTX + VCALL_OFFSET).  */
+  if (vcall_offset)
     {
-      switch (GET_CODE (insn))
+      rtx vcall_offset_rtx = GEN_INT (vcall_offset);
+      rtx scratch = gen_rtx_REG (Pmode, 1);
+
+      gcc_assert (vcall_offset < 0);
+
+      /* SCRATCH = *THIS_RTX.  */
+      emit_move_insn (scratch, gen_rtx_MEM (Pmode, this_rtx));
+
+      /* Prepare for adding VCALL_OFFSET.  The difficulty is that we
+        may not have any available scratch register at this point.  */
+      if (SPARC_SIMM13_P (vcall_offset))
+       ;
+      /* This is the case if ARCH64 (unless -ffixed-g5 is passed).  */
+      else if (! fixed_regs[5]
+              /* The below sequence is made up of at least 2 insns,
+                 while the default method may need only one.  */
+              && vcall_offset < -8192)
        {
-       case JUMP_INSN:
-       case NOTE:
-         break;
-       case CODE_LABEL:
-       case CALL_INSN:
-       default:
-         if (! set_once)
-           return 0;
-         break;
-       case INSN:
-         {
-           rtx pat = PATTERN (insn);
-           if (GET_CODE (pat) != SET)
-             return 0;
-           if (rtx_equal_p (x, SET_DEST (pat)))
-             return set_extends (insn);
-           if (y && rtx_equal_p (y, SET_DEST (pat)))
-             return set_extends (insn);
-           if (reg_overlap_mentioned_p (SET_DEST (pat), y))
-             return 0;
-         }
+         rtx scratch2 = gen_rtx_REG (Pmode, 5);
+         emit_move_insn (scratch2, vcall_offset_rtx);
+         vcall_offset_rtx = scratch2;
+       }
+      else
+       {
+         rtx increment = GEN_INT (-4096);
+
+         /* VCALL_OFFSET is a negative number whose typical range can be
+            estimated as -32768..0 in 32-bit mode.  In almost all cases
+            it is therefore cheaper to emit multiple add insns than
+            spilling and loading the constant into a register (at least
+            6 insns).  */
+         while (! SPARC_SIMM13_P (vcall_offset))
+           {
+             emit_insn (gen_add2_insn (scratch, increment));
+             vcall_offset += 4096;
+           }
+         vcall_offset_rtx = GEN_INT (vcall_offset); /* cannot be 0 */
        }
+
+      /* SCRATCH = *(*THIS_RTX + VCALL_OFFSET).  */
+      emit_move_insn (scratch, gen_rtx_MEM (Pmode,
+                                           gen_rtx_PLUS (Pmode,
+                                                         scratch,
+                                                         vcall_offset_rtx)));
+
+      /* THIS_RTX += *(*THIS_RTX + VCALL_OFFSET).  */
+      emit_insn (gen_add2_insn (this_rtx, scratch));
     }
-  return 0;
-}
 
-char *
-sparc_v8plus_shift (operands, insn, opcode)
-     rtx *operands;
-     rtx insn;
-     const char *opcode;
-{
-  static char asm_code[60];
+  /* Generate a tail call to the target function.  */
+  if (! TREE_USED (function))
+    {
+      assemble_external (function);
+      TREE_USED (function) = 1;
+    }
+  funexp = XEXP (DECL_RTL (function), 0);
 
-  if (GET_CODE (operands[3]) == SCRATCH)
-    operands[3] = operands[0];
-  if (GET_CODE (operands[1]) == CONST_INT)
+  if (flag_delayed_branch)
     {
-      output_asm_insn ("mov\t%1, %3", operands);
+      funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
+      insn = emit_call_insn (gen_sibcall (funexp));
+      SIBLING_CALL_P (insn) = 1;
     }
   else
     {
-      output_asm_insn ("sllx\t%H1, 32, %3", operands);
-      if (sparc_check_64 (operands[1], insn) <= 0)
-       output_asm_insn ("srl\t%L1, 0, %L1", operands);
-      output_asm_insn ("or\t%L1, %3, %3", operands);
+      /* The hoops we have to jump through in order to generate a sibcall
+        without using delay slots...  */
+      rtx spill_reg, spill_reg2, seq, scratch = gen_rtx_REG (Pmode, 1);
+
+      if (flag_pic)
+        {
+         spill_reg = gen_rtx_REG (word_mode, 15);  /* %o7 */
+         spill_reg2 = gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM);
+         start_sequence ();
+         /* Delay emitting the PIC helper function because it needs to
+            change the section and we are emitting assembly code.  */
+         load_pic_register (true);  /* clobbers %o7 */
+         scratch = legitimize_pic_address (funexp, scratch);
+         seq = get_insns ();
+         end_sequence ();
+         emit_and_preserve (seq, spill_reg, spill_reg2);
+       }
+      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, 0);
+             break;
+
+           default:
+             gcc_unreachable ();
+           }
+       }
+
+      emit_jump_insn (gen_indirect_jump (scratch));
     }
 
-  strcpy(asm_code, opcode);
-  if (which_alternative != 2)
-    return strcat (asm_code, "\t%0, %2, %L0\n\tsrlx\t%L0, 32, %H0");
-  else
-    return strcat (asm_code, "\t%3, %2, %3\n\tsrlx\t%3, 32, %H0\n\tmov\t%3, %L0");
+  emit_barrier ();
+
+  /* Run just enough of rest_of_compilation to get the insns emitted.
+     There's not really enough bulk here to make other passes such as
+     instruction scheduling worth while.  Note that use_thunk calls
+     assemble_start_function and assemble_end_function.  */
+  insn = get_insns ();
+  insn_locators_alloc ();
+  shorten_branches (insn);
+  final_start_function (insn, file, 1);
+  final (insn, file, 1);
+  final_end_function ();
+  free_after_compilation (cfun);
+
+  reload_completed = 0;
+  epilogue_completed = 0;
 }
-\f
-/* Output rtl to increment the profiler label LABELNO
-   for profiling a function entry.  */
 
-void
-sparc_profile_hook (labelno)
-     int labelno;
+/* Return true if sparc_output_mi_thunk would be able to output the
+   assembler code for the thunk function specified by the arguments
+   it is passed, and false otherwise.  */
+static bool
+sparc_can_output_mi_thunk (const_tree thunk_fndecl ATTRIBUTE_UNUSED,
+                          HOST_WIDE_INT delta ATTRIBUTE_UNUSED,
+                          HOST_WIDE_INT vcall_offset,
+                          const_tree function ATTRIBUTE_UNUSED)
 {
-  char buf[32];
-  rtx lab, fun;
+  /* Bound the loop used in the default method above.  */
+  return (vcall_offset >= -32768 || ! fixed_regs[5]);
+}
 
-  ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
-  lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
-  fun = gen_rtx_SYMBOL_REF (Pmode, MCOUNT_FUNCTION);
+/* How to allocate a 'struct machine_function'.  */
 
-  emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode);
+static struct machine_function *
+sparc_init_machine_status (void)
+{
+  return GGC_CNEW (struct machine_function);
 }
-\f
-/* Mark ARG, which is really a struct ultrasparc_pipline_state *, for
-   GC.  */
 
-static void
-mark_ultrasparc_pipeline_state (arg)
-     void *arg;
+/* 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)
 {
-  struct ultrasparc_pipeline_state *ups;
-  size_t i;
+  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;
 
-  ups = (struct ultrasparc_pipeline_state *) arg;
-  for (i = 0; i < sizeof (ups->group) / sizeof (rtx); ++i)
-    ggc_mark_rtx (ups->group[i]);
+  gcc_unreachable ();
 }
 
-/* Called to register all of our global variables with the garbage
-   collector.  */
+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;
+}
 
+/* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook.
+   This is called from dwarf2out.c to emit call frame instructions
+   for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs. */
 static void
-sparc_add_gc_roots ()
+sparc_dwarf_handle_frame_unspec (const char *label,
+                                rtx pattern ATTRIBUTE_UNUSED,
+                                int index ATTRIBUTE_UNUSED)
 {
-  ggc_add_rtx_root (&sparc_compare_op0, 1);
-  ggc_add_rtx_root (&sparc_compare_op1, 1);
-  ggc_add_rtx_root (&global_offset_table, 1);
-  ggc_add_rtx_root (&get_pc_symbol, 1);
-  ggc_add_rtx_root (&sparc_addr_diff_list, 1);
-  ggc_add_rtx_root (&sparc_addr_list, 1);
-  ggc_add_root (ultra_pipe_hist, ARRAY_SIZE (ultra_pipe_hist),
-               sizeof (ultra_pipe_hist[0]), &mark_ultrasparc_pipeline_state);
+  gcc_assert (index == UNSPECV_SAVEW);
+  dwarf2out_window_save (label);
 }
 
-#ifdef OBJECT_FORMAT_ELF
+/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
+   We need to emit DTP-relative relocations.  */
+
 static void
-sparc_elf_asm_named_section (name, flags)
-     const char *name;
-     unsigned int flags;
+sparc_output_dwarf_dtprel (FILE *file, int size, rtx x)
 {
-  if (flags & SECTION_MERGE)
+  switch (size)
     {
-      /* entsize cannot be expressed in this section attributes
-        encoding style.  */
-      default_elf_asm_named_section (name, flags);
-      return;
+    case 4:
+      fputs ("\t.word\t%r_tls_dtpoff32(", file);
+      break;
+    case 8:
+      fputs ("\t.xword\t%r_tls_dtpoff64(", file);
+      break;
+    default:
+      gcc_unreachable ();
     }
+  output_addr_const (file, x);
+  fputs (")", file);
+}
 
-  fprintf (asm_out_file, "\t.section\t\"%s\"", name);
-
-  if (!(flags & SECTION_DEBUG))
-    fputs (",#alloc", asm_out_file);
-  if (flags & SECTION_WRITE)
-    fputs (",#write", asm_out_file);
-  if (flags & SECTION_CODE)
-    fputs (",#execinstr", asm_out_file);
+/* Do whatever processing is required at the end of a file.  */
 
-  /* ??? Handle SECTION_BSS.  */
+static void
+sparc_file_end (void)
+{
+  /* If we haven't emitted the special PIC helper function, do so now.  */
+  if (pic_helper_symbol_name[0] && !pic_helper_emitted_p)
+    emit_pic_helper ();
 
-  fputc ('\n', asm_out_file);
+  if (NEED_INDICATE_EXEC_STACK)
+    file_end_indicate_exec_stack ();
 }
-#endif /* OBJECT_FORMAT_ELF */
 
-int
-sparc_extra_constraint_check (op, c, strict)
-     rtx op;
-     int c;
-     int strict;
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+/* Implement TARGET_MANGLE_TYPE.  */
+
+static const char *
+sparc_mangle_type (const_tree type)
 {
-  int reload_ok_mem;
+  if (!TARGET_64BIT
+      && TYPE_MAIN_VARIANT (type) == long_double_type_node
+      && TARGET_LONG_DOUBLE_128)
+    return "g";
 
-  if (TARGET_ARCH64
-      && (c == 'T' || c == 'U'))
-    return 0;
+  /* For all other types, use normal C++ mangling.  */
+  return NULL;
+}
+#endif
 
-  switch (c)
-    {
-    case 'Q':
-      return fp_sethi_p (op);
+/* Expand code to perform a 8 or 16-bit compare and swap by doing 32-bit
+   compare and swap on the word containing the byte or half-word.  */
 
-    case 'R':
-      return fp_mov_p (op);
+void
+sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
+{
+  rtx addr1 = force_reg (Pmode, XEXP (mem, 0));
+  rtx addr = gen_reg_rtx (Pmode);
+  rtx off = gen_reg_rtx (SImode);
+  rtx oldv = gen_reg_rtx (SImode);
+  rtx newv = gen_reg_rtx (SImode);
+  rtx oldvalue = gen_reg_rtx (SImode);
+  rtx newvalue = gen_reg_rtx (SImode);
+  rtx res = gen_reg_rtx (SImode);
+  rtx resv = gen_reg_rtx (SImode);
+  rtx memsi, val, mask, end_label, loop_label, cc;
+
+  emit_insn (gen_rtx_SET (VOIDmode, addr,
+                         gen_rtx_AND (Pmode, addr1, GEN_INT (-4))));
+
+  if (Pmode != SImode)
+    addr1 = gen_lowpart (SImode, addr1);
+  emit_insn (gen_rtx_SET (VOIDmode, off,
+                         gen_rtx_AND (SImode, addr1, GEN_INT (3))));
+
+  memsi = gen_rtx_MEM (SImode, addr);
+  set_mem_alias_set (memsi, ALIAS_SET_MEMORY_BARRIER);
+  MEM_VOLATILE_P (memsi) = MEM_VOLATILE_P (mem);
+
+  val = force_reg (SImode, memsi);
+
+  emit_insn (gen_rtx_SET (VOIDmode, off,
+                         gen_rtx_XOR (SImode, off,
+                                      GEN_INT (GET_MODE (mem) == QImode
+                                               ? 3 : 2))));
+
+  emit_insn (gen_rtx_SET (VOIDmode, off,
+                         gen_rtx_ASHIFT (SImode, off, GEN_INT (3))));
+
+  if (GET_MODE (mem) == QImode)
+    mask = force_reg (SImode, GEN_INT (0xff));
+  else
+    mask = force_reg (SImode, GEN_INT (0xffff));
 
-    case 'S':
-      return fp_high_losum_p (op);
+  emit_insn (gen_rtx_SET (VOIDmode, mask,
+                         gen_rtx_ASHIFT (SImode, mask, off)));
 
-    case 'U':
-      if (! strict
-         || (GET_CODE (op) == REG
-             && (REGNO (op) < FIRST_PSEUDO_REGISTER
-                 || reg_renumber[REGNO (op)] >= 0)))
-       return register_ok_for_ldd (op);
+  emit_insn (gen_rtx_SET (VOIDmode, val,
+                         gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask),
+                                      val)));
 
-      return 0;
+  oldval = gen_lowpart (SImode, oldval);
+  emit_insn (gen_rtx_SET (VOIDmode, oldv,
+                         gen_rtx_ASHIFT (SImode, oldval, off)));
 
-    case 'W':
-    case 'T':
-      break;
+  newval = gen_lowpart_common (SImode, newval);
+  emit_insn (gen_rtx_SET (VOIDmode, newv,
+                         gen_rtx_ASHIFT (SImode, newval, off)));
 
-    default:
-      return 0;
-    }
+  emit_insn (gen_rtx_SET (VOIDmode, oldv,
+                         gen_rtx_AND (SImode, oldv, mask)));
 
-  /* Our memory extra constraints have to emulate the
-     behavior of 'm' and 'o' in order for reload to work
-     correctly.  */
-  if (GET_CODE (op) == MEM)
-    {
-      reload_ok_mem = 0;
-      if ((TARGET_ARCH64 || mem_min_alignment (op, 8))
-         && (! strict
-             || strict_memory_address_p (Pmode, XEXP (op, 0))))
-       reload_ok_mem = 1;
-    }
-  else
-    {
-      reload_ok_mem = (reload_in_progress
-                      && GET_CODE (op) == REG
-                      && REGNO (op) >= FIRST_PSEUDO_REGISTER
-                      && reg_renumber [REGNO (op)] < 0);
-    }
+  emit_insn (gen_rtx_SET (VOIDmode, newv,
+                         gen_rtx_AND (SImode, newv, mask)));
 
-  return reload_ok_mem;
-}
+  end_label = gen_label_rtx ();
+  loop_label = gen_label_rtx ();
+  emit_label (loop_label);
 
-/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
-   Used for C++ multiple inheritance.  */
+  emit_insn (gen_rtx_SET (VOIDmode, oldvalue,
+                         gen_rtx_IOR (SImode, oldv, val)));
 
-void
-sparc_output_mi_thunk (file, thunk_fndecl, delta, function)
-     FILE *file;
-     tree thunk_fndecl ATTRIBUTE_UNUSED;
-     HOST_WIDE_INT delta;
-     tree function;
-{
-  rtx this, insn, funexp, delta_rtx, tmp;
+  emit_insn (gen_rtx_SET (VOIDmode, newvalue,
+                         gen_rtx_IOR (SImode, newv, val)));
 
-  reload_completed = 1;
-  no_new_pseudos = 1;
-  current_function_uses_only_leaf_regs = 1;
+  emit_insn (gen_sync_compare_and_swapsi (res, memsi, oldvalue, newvalue));
 
-  emit_note (NULL, NOTE_INSN_PROLOGUE_END);
+  emit_cmp_and_jump_insns (res, oldvalue, EQ, NULL, SImode, 0, end_label);
 
-  /* 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);
-  else
-    this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST);
+  emit_insn (gen_rtx_SET (VOIDmode, resv,
+                         gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask),
+                                      res)));
 
-  /* Add DELTA.  When possible use a plain add, otherwise load it into
-     a register first.  */
-  delta_rtx = GEN_INT (delta);
-  if (!SPARC_SIMM13_P (delta))
-    {
-      rtx scratch = gen_rtx_REG (Pmode, 1);
-      if (TARGET_ARCH64)
-       sparc_emit_set_const64 (scratch, delta_rtx);
-      else
-       sparc_emit_set_const32 (scratch, delta_rtx);
-      delta_rtx = scratch;
-    }
+  sparc_compare_op0 = resv;
+  sparc_compare_op1 = val;
+  cc = gen_compare_reg (NE);
 
-  tmp = gen_rtx_PLUS (Pmode, this, delta_rtx);
-  emit_insn (gen_rtx_SET (VOIDmode, this, tmp));
+  emit_insn (gen_rtx_SET (VOIDmode, val, resv));
 
-  /* Generate a tail call to the target function.  */
-  if (! TREE_USED (function))
-    {
-      assemble_external (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;
-  emit_barrier ();
+  sparc_compare_emitted = cc;
+  emit_jump_insn (gen_bne (loop_label));
 
-  /* Run just enough of rest_of_compilation to get the insns emitted.
-     There's not really enough bulk here to make other passes such as
-     instruction scheduling worth while.  Note that use_thunk calls
-     assemble_start_function and assemble_end_function.  */
-  insn = get_insns ();
-  shorten_branches (insn);
-  final_start_function (insn, file, 1);
-  final (insn, file, 1, 0);
-  final_end_function ();
+  emit_label (end_label);
 
-  reload_completed = 0;
-  no_new_pseudos = 0;
+  emit_insn (gen_rtx_SET (VOIDmode, res,
+                         gen_rtx_AND (SImode, res, mask)));
+
+  emit_insn (gen_rtx_SET (VOIDmode, res,
+                         gen_rtx_LSHIFTRT (SImode, res, off)));
+
+  emit_move_insn (result, gen_lowpart (GET_MODE (result), res));
 }
+
+#include "gt-sparc.h"