OSDN Git Service

* config/alpha/alpha.c (alpha_use_dfa_pipeline_interface): Remove.
[pf3gnuchains/gcc-fork.git] / gcc / config / sparc / sparc.c
index 6002a5d..5439f03 100644 (file)
@@ -47,24 +47,25 @@ Boston, MA 02111-1307, USA.  */
 #include "target.h"
 #include "target-def.h"
 #include "cfglayout.h"
+#include "tree-gimple.h"
 
-/* 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.  */
-
-#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 HOST_WIDE_INT apparent_fsize;
@@ -74,14 +75,13 @@ static HOST_WIDE_INT actual_fsize;
    saved (as 4-byte quantities).  */
 static int num_gfregs;
 
+/* The alias set for prologue/epilogue register save/restore.  */
+static GTY(()) int sparc_sr_alias_set;
+
 /* Save the operands last given to a compare for use when we
    generate a scc or bcc insn.  */
 rtx sparc_compare_op0, sparc_compare_op1;
 
-/* Coordinate with the md file wrt special insns created by
-   sparc_nonflat_function_epilogue.  */
-bool sparc_emitting_epilogue;
-
 /* Vector to say how input registers are mapped to output registers.
    HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to
    eliminate it.  You must use -fomit-frame-pointer to get that.  */
@@ -125,18 +125,16 @@ struct machine_function GTY(())
   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.  */
+/* 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 const char *frame_base_name;
+static rtx frame_base_reg;
 static HOST_WIDE_INT frame_base_offset;
 
 static void sparc_init_modes (void);
-static int save_regs (FILE *, int, int, const char *, int, int, HOST_WIDE_INT);
-static int restore_regs (FILE *, int, int, const char *, int, int);
-static void build_big_number (FILE *, HOST_WIDE_INT, const char *);
+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 *);
 
@@ -146,34 +144,23 @@ 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 int check_return_regs (rtx);
+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 output_restore_regs (FILE *, int);
-static void sparc_output_function_prologue (FILE *, HOST_WIDE_INT);
-static void sparc_output_function_epilogue (FILE *, HOST_WIDE_INT);
-static void sparc_flat_function_epilogue (FILE *, HOST_WIDE_INT);
-static void sparc_flat_function_prologue (FILE *, HOST_WIDE_INT);
-static void sparc_flat_save_restore (FILE *, const char *, int,
-                                    unsigned long, unsigned long,
-                                    const char *, const char *,
-                                    HOST_WIDE_INT);
-static void sparc_nonflat_function_epilogue (FILE *, HOST_WIDE_INT, int);
-static void sparc_nonflat_function_prologue (FILE *, HOST_WIDE_INT, int);
+static void load_pic_register (void);
+static int save_or_restore_regs (int, int, rtx, int, int);
+static void emit_save_regs (void);
+static void emit_restore_regs (void);
+static void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT);
+static void sparc_asm_function_epilogue (FILE *, HOST_WIDE_INT);
 #ifdef OBJECT_FORMAT_ELF
 static void sparc_elf_asm_named_section (const char *, unsigned int);
 #endif
-static void sparc_aout_select_section (tree, int, unsigned HOST_WIDE_INT)
-     ATTRIBUTE_UNUSED;
-static void sparc_aout_select_rtx_section (enum machine_mode, rtx,
-                                          unsigned HOST_WIDE_INT)
-     ATTRIBUTE_UNUSED;
 
 static int sparc_adjust_cost (rtx, rtx, rtx, int);
 static int sparc_issue_rate (void);
 static void sparc_sched_init (FILE *, int, int);
-static int sparc_use_dfa_pipeline_interface (void);
 static int sparc_use_sched_lookahead (void);
 
 static void emit_soft_tfmode_libcall (const char *, int, rtx *);
@@ -193,6 +180,11 @@ static rtx sparc_tls_got (void);
 static const char *get_some_local_dynamic_name (void);
 static int get_some_local_dynamic_name_1 (rtx *, void *);
 static bool sparc_rtx_costs (rtx, int, int, int *);
+static bool sparc_promote_prototypes (tree);
+static rtx sparc_struct_value_rtx (tree, int);
+static bool sparc_return_in_memory (tree, tree);
+static bool sparc_strict_argument_naming (CUMULATIVE_ARGS *);
+static tree sparc_gimplify_va_arg (tree, tree, tree *, tree *);
 \f
 /* Option handling.  */
 
@@ -238,9 +230,9 @@ enum processor_type sparc_cpu;
 #define TARGET_ASM_INTEGER sparc_assemble_integer
 
 #undef TARGET_ASM_FUNCTION_PROLOGUE
-#define TARGET_ASM_FUNCTION_PROLOGUE sparc_output_function_prologue
+#define TARGET_ASM_FUNCTION_PROLOGUE sparc_asm_function_prologue
 #undef TARGET_ASM_FUNCTION_EPILOGUE
-#define TARGET_ASM_FUNCTION_EPILOGUE sparc_output_function_epilogue
+#define TARGET_ASM_FUNCTION_EPILOGUE sparc_asm_function_epilogue
 
 #undef TARGET_SCHED_ADJUST_COST
 #define TARGET_SCHED_ADJUST_COST sparc_adjust_cost
@@ -249,7 +241,7 @@ enum processor_type sparc_cpu;
 #undef TARGET_SCHED_INIT
 #define TARGET_SCHED_INIT sparc_sched_init
 #undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
-#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE sparc_use_dfa_pipeline_interface
+#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE hook_int_void_1
 #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD sparc_use_sched_lookahead
 
@@ -276,6 +268,37 @@ enum processor_type sparc_cpu;
 #undef TARGET_ADDRESS_COST
 #define TARGET_ADDRESS_COST hook_int_rtx_0
 
+/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a
+   no-op for TARGET_ARCH32 this is ok.  Otherwise we'd need to add a runtime
+   test for this value.  */
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+
+/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a
+   no-op for TARGET_ARCH32 this is ok.  Otherwise we'd need to add a runtime
+   test for this value.  */
+#undef TARGET_PROMOTE_FUNCTION_RETURN
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES sparc_promote_prototypes
+
+#undef TARGET_STRUCT_VALUE_RTX
+#define TARGET_STRUCT_VALUE_RTX sparc_struct_value_rtx
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY sparc_return_in_memory
+
+#undef TARGET_EXPAND_BUILTIN_SAVEREGS
+#define TARGET_EXPAND_BUILTIN_SAVEREGS sparc_builtin_saveregs
+#undef TARGET_STRICT_ARGUMENT_NAMING
+#define TARGET_STRICT_ARGUMENT_NAMING sparc_strict_argument_naming
+
+#undef TARGET_GIMPLIFY_VA_ARG_EXPR
+#define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg
+
+#undef TARGET_LATE_RTL_PROLOGUE_EPILOGUE
+#define TARGET_LATE_RTL_PROLOGUE_EPILOGUE true
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Validate and override various options, and do some machine dependent
@@ -475,6 +498,9 @@ sparc_override_options (void)
   /* Do various machine dependent initializations.  */
   sparc_init_modes ();
 
+  /* Acquire a unique set number for our register saves and restores.  */
+  sparc_sr_alias_set = new_alias_set ();
+
   /* Set up function hooks.  */
   init_machine_status = sparc_init_machine_status;
 }
@@ -690,14 +716,6 @@ icc_or_fcc_reg_operand (rtx op, enum machine_mode mode)
   return fcc_reg_operand (op, mode);
 }
 
-/* Nonzero if OP can appear as the dest of a RESTORE insn.  */
-int
-restore_operand (rtx op, enum machine_mode mode)
-{
-  return (GET_CODE (op) == REG && GET_MODE (op) == mode
-         && (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32)));
-}
-
 /* Call insn on SPARC can take a PC-relative constant address, or any regular
    memory address.  */
 
@@ -928,15 +946,16 @@ eq_or_neq (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 int
 normal_comp_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  enum rtx_code code = GET_CODE (op);
+  enum rtx_code code;
 
-  if (GET_RTX_CLASS (code) != '<')
+  if (!COMPARISON_P (op))
     return 0;
 
   if (GET_MODE (XEXP (op, 0)) == CCFPmode
       || GET_MODE (XEXP (op, 0)) == CCFPEmode)
     return 1;
 
+  code = GET_CODE (op);
   return (code != NE && code != EQ && code != GEU && code != LTU);
 }
 
@@ -944,13 +963,14 @@ normal_comp_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
    MATCH_OPERATOR to recognize all the branch insns.  */
 
 int
-noov_compare_op (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+noov_compare_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  enum rtx_code code = GET_CODE (op);
+  enum rtx_code code;
 
-  if (GET_RTX_CLASS (code) != '<')
+  if (!COMPARISON_P (op))
     return 0;
 
+  code = GET_CODE (op);
   if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode
       || GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
     /* These are the only branches which work with CC_NOOVmode.  */
@@ -964,14 +984,15 @@ noov_compare_op (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 int
 noov_compare64_op (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  enum rtx_code code = GET_CODE (op);
+  enum rtx_code code;
 
   if (! TARGET_V9)
     return 0;
 
-  if (GET_RTX_CLASS (code) != '<')
+  if (!COMPARISON_P (op))
     return 0;
 
+  code = GET_CODE (op);
   if (GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
     /* These are the only branches which work with CCX_NOOVmode.  */
     return (code == EQ || code == NE || code == GE || code == LT);
@@ -982,13 +1003,14 @@ noov_compare64_op (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
    conditional move or branch on register contents instructions.  */
 
 int
-v9_regcmp_op (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+v9_regcmp_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  enum rtx_code code = GET_CODE (op);
+  enum rtx_code code;
 
-  if (GET_RTX_CLASS (code) != '<')
+  if (!COMPARISON_P (op))
     return 0;
 
+  code = GET_CODE (op);
   return v9_regcmp_p (code);
 }
 
@@ -1117,7 +1139,7 @@ arith10_operand (rtx op, enum machine_mode mode)
 /* Return true if OP is a register, is a CONST_INT that fits in a 13 bit
    immediate field, or is a CONST_DOUBLE whose both parts fit in a 13 bit
    immediate field.
-   v9: Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
+   ARCH64: Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
    can fit in a 13 bit immediate field.  This is an acceptable DImode operand
    for most 3 address instructions.  */
 
@@ -1263,10 +1285,6 @@ input_operand (rtx op, enum machine_mode mode)
   if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
     return 0;
 
-  /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and result in 0/1.  */
-  if (GET_CODE (op) == CONSTANT_P_RTX)
-    return 1;
-
   /* Allow any one instruction integer constant, and all CONST_INT
      variants when we are working in DImode and !arch64.  */
   if (GET_MODE_CLASS (mode) == MODE_INT
@@ -1335,6 +1353,32 @@ input_operand (rtx op, enum machine_mode mode)
   return 0;
 }
 
+/* Return 1 if OP is valid for the lhs of a compare insn.  */
+
+int
+compare_operand (rtx op, enum machine_mode mode)
+{
+  if (GET_CODE (op) == ZERO_EXTRACT)
+    return (register_operand (XEXP (op, 0), mode)
+           && small_int_or_double (XEXP (op, 1), mode)
+           && small_int_or_double (XEXP (op, 2), mode)
+           /* This matches cmp_zero_extract.  */
+           && ((mode == SImode
+                && ((GET_CODE (XEXP (op, 2)) == CONST_INT
+                     && INTVAL (XEXP (op, 2)) > 19)
+                    || (GET_CODE (XEXP (op, 2)) == CONST_DOUBLE
+                        && CONST_DOUBLE_LOW (XEXP (op, 2)) > 19)))
+               /* This matches cmp_zero_extract_sp64.  */
+               || (mode == DImode
+                   && TARGET_ARCH64
+                   && ((GET_CODE (XEXP (op, 2)) == CONST_INT
+                        && INTVAL (XEXP (op, 2)) > 51)
+                       || (GET_CODE (XEXP (op, 2)) == CONST_DOUBLE
+                           && CONST_DOUBLE_LOW (XEXP (op, 2)) > 51)))));
+  else
+    return register_operand (op, mode);
+}
+
 \f
 /* We know it can't be done in one insn when we get here,
    the movsi expander guarantees this.  */
@@ -2657,7 +2701,7 @@ 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]);
@@ -2708,14 +2752,6 @@ emit_tfmode_cvt (enum rtx_code code, rtx *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 (void)
-{
-  return (actual_fsize == 0);
-}
-
 /* Return nonzero if a branch/jump/call instruction will be emitting
    nop into its delay slot.  */
 
@@ -2735,69 +2771,48 @@ empty_delay_slot (rtx 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 (rtx trial, int slot)
+tls_call_delay (rtx trial)
 {
-  rtx pat, src;
-
-  if (slot >= 1)
-    return 0;
-
-  if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
-    return 0;
-
-  if (get_attr_length (trial) != 1)
-    return 0;
-
-  /* If there are any call-saved registers, we should scan TRIAL if it
-     does not reference them.  For now just make it easy.  */
-  if (num_gfregs)
-    return 0;
-
-  /* If the function uses __builtin_eh_return, the eh_return machinery
-     occupies the delay slot.  */
-  if (current_function_calls_eh_return)
-    return 0;
+  rtx pat, unspec;
 
-  /* In the case of a true leaf function, anything can go into the delay slot.
-     A delay slot only exists however if the frame size is zero, otherwise
-     we will put an insn to adjust the stack after the return.  */
-  if (current_function_uses_only_leaf_regs)
-    {
-      if (leaf_return_peephole_ok ())
-       return ((get_attr_in_uncond_branch_delay (trial)
-                == IN_BRANCH_DELAY_TRUE));
-      return 0;
-    }
+  /* Binutils allows
+     call __tls_get_addr, %tgd_call (foo)
+      add %l7, %o0, %o0, %tgd_add (foo)
+     while Sun as/ld does not.  */
+  if (TARGET_GNU_TLS || !TARGET_TLS)
+    return 1;
 
   pat = PATTERN (trial);
+  if (GET_CODE (pat) != SET || GET_CODE (SET_DEST (pat)) != PLUS)
+    return 1;
 
-  /* Otherwise, only operations which can be done in tandem with
-     a `restore' or `return' insn can go into the delay slot.  */
-  if (GET_CODE (SET_DEST (pat)) != REG
-      || REGNO (SET_DEST (pat)) < 24)
-    return 0;
+  unspec = XEXP (SET_DEST (pat), 1);
+  if (GET_CODE (unspec) != UNSPEC
+      || (XINT (unspec, 1) != UNSPEC_TLSGD
+         && XINT (unspec, 1) != UNSPEC_TLSLDM))
+    return 1;
 
-  /* If this instruction sets up floating point register and we have a return
-     instruction, it can probably go in.  But restore will not work
-     with FP_REGS.  */
-  if (REGNO (SET_DEST (pat)) >= 32)
-    {
-      if (TARGET_V9 && ! epilogue_renumber (&pat, 1)
-         && (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE))
-       return 1;
-      return 0;
-    }
+  return 0;
+}
 
-  /* The set of insns matched here must agree precisely with the set of
-     patterns paired with a RETURN in sparc.md.  */
+/* 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.
 
-  src = SET_SRC (pat);
+   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.  */
+
+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)))
     {
@@ -2807,41 +2822,39 @@ eligible_for_epilogue_delay (rtx trial, int 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)
@@ -2851,7 +2864,7 @@ eligible_for_epilogue_delay (rtx trial, int slot)
                   && immediate_operand (XEXP (src, 1), DImode))))
     return 1;
 
-  /* sll{,x} reg,1,reg2 is add reg,reg,reg2 as well.  */
+  /* The 'restore src,src,dest' pattern.  */
   else if (GET_CODE (src) == ASHIFT
           && (register_operand (XEXP (src, 0), SImode)
               || register_operand (XEXP (src, 0), DImode))
@@ -2861,39 +2874,64 @@ eligible_for_epilogue_delay (rtx trial, int slot)
   return 0;
 }
 
-/* Return nonzero if TRIAL can go into the call delay slot.  */
+/* Return nonzero if TRIAL can go into the function return's
+   delay slot.  */
+
 int
-tls_call_delay (rtx trial)
+eligible_for_return_delay (rtx trial)
 {
-  rtx pat, unspec;
+  int leaf_function_p = current_function_uses_only_leaf_regs;
+  rtx pat;
 
-  /* 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 (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
+    return 0;
+
+  if (get_attr_length (trial) != 1)
+    return 0;
+
+  /* If there are any call-saved registers, we should scan TRIAL if it
+     does not reference them.  For now just make it easy.  */
+  if (num_gfregs)
+    return 0;
+
+  /* If the function uses __builtin_eh_return, the eh_return machinery
+     occupies the delay slot.  */
+  if (current_function_calls_eh_return)
+    return 0;
+
+  /* In the case of a true leaf function, anything can go into the slot.  */
+  if (leaf_function_p)
+    return get_attr_in_uncond_branch_delay (trial)
+          == IN_UNCOND_BRANCH_DELAY_TRUE;
 
   pat = PATTERN (trial);
-  if (GET_CODE (pat) != SET || GET_CODE (SET_DEST (pat)) != PLUS)
-    return 1;
 
-  unspec = XEXP (SET_DEST (pat), 1);
-  if (GET_CODE (unspec) != UNSPEC
-      || (XINT (unspec, 1) != UNSPEC_TLSGD
-         && XINT (unspec, 1) != UNSPEC_TLSLDM))
-    return 1;
+  /* 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;
 
-  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 (rtx trial)
 {
-  rtx pat, src;
+  int leaf_function_p = current_function_uses_only_leaf_regs;
+  rtx pat;
 
   if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
     return 0;
@@ -2903,11 +2941,11 @@ eligible_for_sibcall_delay (rtx trial)
 
   pat = PATTERN (trial);
 
-  if (current_function_uses_only_leaf_regs)
+  if (leaf_function_p)
     {
       /* If the tail call is done using the call instruction,
         we have to restore %o7 in the delay slot.  */
-      if ((TARGET_ARCH64 && ! TARGET_CM_MEDLOW) || flag_pic)
+      if (LEAF_SIBCALL_SLOT_RESERVED_P)
        return 0;
 
       /* %g1 is used to build the function address */
@@ -2920,7 +2958,7 @@ eligible_for_sibcall_delay (rtx 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;
 
@@ -2929,89 +2967,7 @@ eligible_for_sibcall_delay (rtx trial)
   if (reg_mentioned_p (gen_rtx_REG (Pmode, 15), pat))
     return 0;
 
-  src = SET_SRC (pat);
-
-  if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
-      && arith_operand (src, GET_MODE (src)))
-    {
-      if (TARGET_ARCH64)
-        return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
-      else
-        return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
-    }
-
-  else if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
-          && arith_double_operand (src, GET_MODE (src)))
-    return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
-
-  else if (! TARGET_FPU && restore_operand (SET_DEST (pat), SFmode)
-          && register_operand (src, SFmode))
-    return 1;
-
-  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;
-
-  else if (GET_CODE (src) == PLUS
-          && arith_double_operand (XEXP (src, 0), DImode)
-          && arith_double_operand (XEXP (src, 1), DImode)
-          && (register_operand (XEXP (src, 0), DImode)
-              || register_operand (XEXP (src, 1), DImode)))
-    return 1;
-
-  else if (GET_CODE (src) == LO_SUM
-          && ! TARGET_CM_MEDMID
-          && ((register_operand (XEXP (src, 0), SImode)
-               && immediate_operand (XEXP (src, 1), SImode))
-              || (TARGET_ARCH64
-                  && register_operand (XEXP (src, 0), DImode)
-                  && immediate_operand (XEXP (src, 1), DImode))))
-    return 1;
-
-  else if (GET_CODE (src) == ASHIFT
-          && (register_operand (XEXP (src, 0), SImode)
-              || register_operand (XEXP (src, 0), DImode))
-          && XEXP (src, 1) == const1_rtx)
-    return 1;
-
-  return 0;
-}
-
-static int
-check_return_regs (rtx x)
-{
-  switch (GET_CODE (x))
-    {
-    case REG:
-      return IN_OR_GLOBAL_P (x);
-
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case CONST:
-    case SYMBOL_REF:
-    case LABEL_REF:
-    return 1;
-
-    case SET:
-    case IOR:
-    case AND:
-    case XOR:
-    case PLUS:
-    case MINUS:
-      if (check_return_regs (XEXP (x, 1)) == 0)
-  return 0;
-    case NOT:
-    case NEG:
-    case MEM:
-      return check_return_regs (XEXP (x, 0));
-      
-    default:
-      return 0;
-    }
-
+  return eligible_for_restore_insn (trial, false);
 }
 
 int
@@ -3043,7 +2999,7 @@ reg_unused_after (rtx reg, rtx insn)
       if (GET_CODE (insn) == CODE_LABEL)
        return 1;
 
-      if (GET_RTX_CLASS (code) == 'i')
+      if (INSN_P (insn))
        {
          rtx set = single_set (insn);
          int in_src = set && reg_overlap_mentioned_p (reg, SET_SRC (set));
@@ -3102,8 +3058,8 @@ sparc_cannot_force_const_mem (rtx x)
 static GTY(()) rtx global_offset_table;
 
 /* The function we use to get at it.  */
-static GTY(()) rtx get_pc_symbol;
-static char get_pc_symbol_name[256];
+static GTY(()) rtx add_pc_to_pic_symbol;
+static GTY(()) char add_pc_to_pic_symbol_name[256];
 
 /* Ensure that we are not using patterns that are not OK with PIC.  */
 
@@ -3681,41 +3637,38 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
   return x;
 }
 
-/* Emit special PIC prologues.  */
+/* Emit the special PIC prologue.  */
 
-void
+static void
 load_pic_register (void)
 {
-  /* Labels to get the PC in the prologue of this function.  */
   int orig_flag_pic = flag_pic;
 
-  if (! flag_pic)
-    abort ();
-
-  /* If we haven't emitted the special get_pc helper function, do so now.  */
-  if (get_pc_symbol_name[0] == 0)
+  /* If we haven't emitted the special helper function, do so now.  */
+  if (add_pc_to_pic_symbol_name[0] == 0)
     {
+      const char *pic_name = reg_names[REGNO (pic_offset_table_rtx)];
       int align;
 
-      ASM_GENERATE_INTERNAL_LABEL (get_pc_symbol_name, "LGETPC", 0);
+      ASM_GENERATE_INTERNAL_LABEL (add_pc_to_pic_symbol_name, "LADDPC", 0);
       text_section ();
 
       align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
       if (align > 0)
        ASM_OUTPUT_ALIGN (asm_out_file, align);
-      (*targetm.asm_out.internal_label) (asm_out_file, "LGETPC", 0);
-      fputs ("\tretl\n\tadd\t%o7, %l7, %l7\n", asm_out_file);
+      ASM_OUTPUT_LABEL (asm_out_file, add_pc_to_pic_symbol_name);
+      fprintf (asm_out_file, "\tjmp %%o7+8\n\t add\t%%o7, %s, %s\n",
+              pic_name, pic_name);
     }
 
   /* Initialize every time through, since we can't easily
      know this to be permanent.  */
   global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
-  get_pc_symbol = gen_rtx_SYMBOL_REF (Pmode, get_pc_symbol_name);
-  flag_pic = 0;
-
-  emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
-                        get_pc_symbol));
+  add_pc_to_pic_symbol = gen_rtx_SYMBOL_REF (Pmode, add_pc_to_pic_symbol_name);
 
+  flag_pic = 0;
+  emit_insn (gen_load_pcrel_sym (pic_offset_table_rtx, global_offset_table,
+                                add_pc_to_pic_symbol));
   flag_pic = orig_flag_pic;
 
   /* Need to emit this whether or not we obey regdecls,
@@ -3992,156 +3945,44 @@ sparc_init_modes (void)
     }
 }
 \f
-/* Save non call used registers from LOW to HIGH at BASE+OFFSET.
-   N_REGS is the number of 4-byte regs saved thus far.  This applies even to
-   v9 int regs as it simplifies the code.  */
+/* Compute the frame size required by the function.  This function is called
+   during the reload pass and also by sparc_expand_prologue.  */
 
-static int
-save_regs (FILE *file, int low, int high, const char *base,
-          int offset, int n_regs, HOST_WIDE_INT real_offset)
+HOST_WIDE_INT
+sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function_p)
 {
+  int outgoing_args_size = (current_function_outgoing_args_size
+                           + REG_PARM_STACK_SPACE (current_function_decl));
+  int n_regs = 0;  /* N_REGS is the number of 4-byte regs saved thus far.  */
   int i;
 
-  if (TARGET_ARCH64 && high <= 32)
+  if (TARGET_ARCH64)
     {
-      for (i = low; i < high; i++)
-       {
-         if (regs_ever_live[i] && ! call_used_regs[i])
-           {
-             fprintf (file, "\tstx\t%s, [%s+%d]\n",
-                      reg_names[i], base, offset + 4 * n_regs);
-             if (dwarf2out_do_frame ())
-               dwarf2out_reg_save ("", i, real_offset + 4 * n_regs);
-             n_regs += 2;
-           }
-       }
+      for (i = 0; i < 8; i++)
+       if (regs_ever_live[i] && ! call_used_regs[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, "\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;
-               }
-           }
-       }
+      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]))
+         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.  */
+  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]))
+      n_regs += 2;
 
-static int
-restore_regs (FILE *file, int low, int high, const char *base,
-             int offset, int n_regs)
-{
-  int i;
+  /* Set up values for use in prologue and epilogue.  */
+  num_gfregs = n_regs;
 
-  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().  */
-
-HOST_WIDE_INT
-compute_frame_size (HOST_WIDE_INT size, int leaf_function)
-{
-  int n_regs = 0, i;
-  int outgoing_args_size = (current_function_outgoing_args_size
-                           + REG_PARM_STACK_SPACE (current_function_decl));
-
-  /* N_REGS is the number of 4-byte regs saved thus far.  This applies
-     even to v9 int regs to be consistent with save_regs/restore_regs.  */
-
-  if (TARGET_ARCH64)
-    {
-      for (i = 0; i < 8; i++)
-       if (regs_ever_live[i] && ! call_used_regs[i])
-         n_regs += 2;
-    }
-  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]))
-         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]))
-      n_regs += 2;
-
-  /* Set up values for use in `function_epilogue'.  */
-  num_gfregs = n_regs;
-
-  if (leaf_function && n_regs == 0
-      && size == 0 && current_function_outgoing_args_size == 0)
-    {
-      actual_fsize = apparent_fsize = 0;
-    }
+  if (leaf_function_p
+      && n_regs == 0
+      && size == 0
+      && current_function_outgoing_args_size == 0)
+    actual_fsize = apparent_fsize = 0;
   else
     {
       /* We subtract STARTING_FRAME_OFFSET, remember it's negative.  */
@@ -4154,106 +3995,14 @@ compute_frame_size (HOST_WIDE_INT size, int leaf_function)
      If a SAVE must be done, or there is a stack-local variable,
      the register window area must be allocated.
      ??? For v8 we apparently need an additional 8 bytes of reserved space.  */
-  if (leaf_function == 0 || size > 0)
+  if (! leaf_function_p || size > 0)
     actual_fsize += (16 * UNITS_PER_WORD) + (TARGET_ARCH64 ? 0 : 8);
 
   return SPARC_STACK_ALIGN (actual_fsize);
 }
 
-/* Build big number NUM in register REG and output the result to FILE.
-   REG is guaranteed to be the only clobbered register.  The function
-   will very likely emit several instructions, so it must not be called
-   from within a delay slot.  */
-
-static void
-build_big_number (FILE *file, HOST_WIDE_INT num, const char *reg)
-{
-#if HOST_BITS_PER_WIDE_INT == 64
-  HOST_WIDE_INT high_bits = (num >> 32) & 0xffffffff;
-
-  if (high_bits == 0
-#else
-  if (num >= 0
-#endif
-      || ! TARGET_ARCH64)
-    {
-      /* We don't use the 'set' macro because it appears to be broken
-        in the Solaris 7 assembler.  */
-      fprintf (file, "\tsethi\t%%hi("HOST_WIDE_INT_PRINT_DEC"), %s\n",
-              num, reg);
-      if ((num & 0x3ff) != 0)
-       fprintf (file, "\tor\t%s, %%lo("HOST_WIDE_INT_PRINT_DEC"), %s\n",
-                reg, num, reg);
-    }
-#if HOST_BITS_PER_WIDE_INT == 64
-  else if (high_bits == 0xffffffff) /* && TARGET_ARCH64 */
-#else
-  else /* num < 0 && TARGET_ARCH64 */
-#endif
-    {
-      /* 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.  */
-      HOST_WIDE_INT inv = ~num;
-      HOST_WIDE_INT low = -0x400 + (num & 0x3ff);
-         
-      fprintf (file, "\tsethi\t%%hi("HOST_WIDE_INT_PRINT_DEC"), %s\n",
-              inv, reg);
-      fprintf (file, "\txor\t%s, "HOST_WIDE_INT_PRINT_DEC", %s\n",
-              reg, low, reg);
-    }
-#if HOST_BITS_PER_WIDE_INT == 64
-  else /* TARGET_ARCH64 */
-    {
-      /* We don't use the 'setx' macro because if requires a scratch register.
-         This is the translation of sparc_emit_set_const64_longway into asm.
-         Hopefully we will soon have prologue/epilogue emitted as RTL.  */
-      HOST_WIDE_INT low1 = (num >> (32 - 12))          & 0xfff;
-      HOST_WIDE_INT low2 = (num >> (32 - 12 - 12))     & 0xfff;
-      HOST_WIDE_INT low3 = (num >> (32 - 12 - 12 - 8)) & 0x0ff;
-      int to_shift = 12;
-
-      /* We don't use the 'set' macro because it appears to be broken
-        in the Solaris 7 assembler.  */
-      fprintf (file, "\tsethi\t%%hi("HOST_WIDE_INT_PRINT_DEC"), %s\n",
-              high_bits, reg);
-      if ((high_bits & 0x3ff) != 0)
-       fprintf (file, "\tor\t%s, %%lo("HOST_WIDE_INT_PRINT_DEC"), %s\n",
-                reg, high_bits, reg);
-
-      if (low1 != 0)
-       {
-         fprintf (file, "\tsllx\t%s, %d, %s\n", reg, to_shift, reg);
-         fprintf (file, "\tor\t%s, "HOST_WIDE_INT_PRINT_DEC", %s\n",
-                  reg, low1, reg);
-         to_shift = 12;
-       }
-      else
-       {
-         to_shift += 12;
-       }
-      if (low2 != 0)
-       {
-         fprintf (file, "\tsllx\t%s, %d, %s\n", reg, to_shift, reg);
-         fprintf (file, "\tor\t%s, "HOST_WIDE_INT_PRINT_DEC", %s\n",
-                  reg, low2, reg);
-         to_shift = 8;
-       }
-      else
-       {
-         to_shift += 8;
-       }
-      fprintf (file, "\tsllx\t%s, %d, %s\n", reg, to_shift, reg);
-      if (low3 != 0)
-       fprintf (file, "\tor\t%s, "HOST_WIDE_INT_PRINT_DEC", %s\n",
-                reg, low3, reg);
-    }
-#endif
-}
-
 /* Output any necessary .register pseudo-ops.  */
+
 void
 sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED)
 {
@@ -4278,105 +4027,260 @@ sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED)
 #endif
 }
 
-/* This function generates the assembly code for function entry.
-   FILE is a stdio stream to output the code to.
-   SIZE is an int: how many units of temporary storage to allocate.
-   Refer to the array `regs_ever_live' to determine which registers
-   to save; `regs_ever_live[I]' is nonzero if register number I
-   is ever used in the function.  This macro is responsible for
-   knowing which registers should not be saved even if used.  */
+/* Save/restore call-saved registers from LOW to HIGH at BASE+OFFSET
+   as needed.  LOW should be double-word aligned for 32-bit registers.
+   Return the new OFFSET.  */
+
+#define SORR_SAVE    0
+#define SORR_RESTORE 1
+
+static int
+save_or_restore_regs (int low, int high, rtx base, int offset, int action)
+{
+  rtx mem, insn;
+  int i;
+
+  if (TARGET_ARCH64 && high <= 32)
+    {
+      for (i = low; i < high; i++)
+       {
+         if (regs_ever_live[i] && ! call_used_regs[i])
+           {
+             mem = gen_rtx_MEM (DImode, plus_constant (base, offset));
+             set_mem_alias_set (mem, sparc_sr_alias_set);
+             if (action == SORR_SAVE)
+               {
+                 insn = emit_move_insn (mem, gen_rtx_REG (DImode, i));
+                 RTX_FRAME_RELATED_P (insn) = 1;
+               }
+             else  /* action == SORR_RESTORE */
+               emit_move_insn (gen_rtx_REG (DImode, i), mem);
+             offset += 8;
+           }
+       }
+    }
+  else
+    {
+      for (i = low; i < high; i += 2)
+       {
+         bool reg0 = regs_ever_live[i] && ! call_used_regs[i];
+         bool reg1 = regs_ever_live[i+1] && ! call_used_regs[i+1];
+         enum machine_mode mode;
+         int regno;
+
+         if (reg0 && reg1)
+           {
+             mode = i < 32 ? DImode : DFmode;
+             regno = i;
+           }
+         else if (reg0)
+           {
+             mode = i < 32 ? SImode : SFmode;
+             regno = i;
+           }
+         else if (reg1)
+           {
+             mode = i < 32 ? SImode : SFmode;
+             regno = i + 1;
+             offset += 4;
+           }
+         else
+           continue;
+
+         mem = gen_rtx_MEM (mode, plus_constant (base, offset));
+         set_mem_alias_set (mem, sparc_sr_alias_set);
+         if (action == SORR_SAVE)
+           {
+             insn = emit_move_insn (mem, gen_rtx_REG (mode, regno));
+             RTX_FRAME_RELATED_P (insn) = 1;
+           }
+         else  /* action == SORR_RESTORE */
+           emit_move_insn (gen_rtx_REG (mode, regno), mem);
 
-/* 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.
+         /* Always preserve double-word alignment.  */
+         offset = (offset + 7) & -8;
+       }
+    }
+
+  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 *file, HOST_WIDE_INT size)
+emit_save_regs (void)
 {
-  if (TARGET_FLAT)
-    sparc_flat_function_prologue (file, size);
+  HOST_WIDE_INT offset;
+  rtx base;
+
+  offset = frame_base_offset - apparent_fsize;
+
+  if (offset < -4096 || offset + num_gfregs * 4 > 4096)
+    {
+      /* ??? 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
-    sparc_nonflat_function_prologue (file, size,
-                                    current_function_uses_only_leaf_regs);
+    base = frame_base_reg;
+
+  offset = save_or_restore_regs (0, 8, base, offset, SORR_SAVE);
+  save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, SORR_SAVE);
 }
 
-/* Output code for the function prologue.  */
+/* Emit code to restore call-saved registers.  */
 
 static void
-sparc_nonflat_function_prologue (FILE *file, HOST_WIDE_INT size,
-                                int leaf_function)
+emit_restore_regs (void)
 {
-  sparc_output_scratch_registers (file);
+  HOST_WIDE_INT offset;
+  rtx base;
+
+  offset = frame_base_offset - apparent_fsize;
+
+  if (offset < -4096 || offset + num_gfregs * 4 > 4096 - 8 /*double*/)
+    {
+      base = gen_rtx_REG (Pmode, 1);
+      emit_move_insn (base, GEN_INT (offset));
+      emit_insn (gen_rtx_SET (VOIDmode,
+                             base,
+                             gen_rtx_PLUS (Pmode, frame_base_reg, base)));
+      offset = 0;
+    }
+  else
+    base = frame_base_reg;
+
+  offset = save_or_restore_regs (0, 8, base, offset, SORR_RESTORE);
+  save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, SORR_RESTORE);
+}
+
+/* Emit an increment for the stack pointer.  */
+
+static void
+emit_stack_pointer_increment (rtx increment)
+{
+  if (TARGET_ARCH64)
+    emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, increment));
+  else
+    emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, increment));
+}
+
+/* Emit a decrement for the stack pointer.  */
+
+static void
+emit_stack_pointer_decrement (rtx decrement)
+{
+  if (TARGET_ARCH64)
+    emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, decrement));
+  else
+    emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, decrement));
+}
+
+/* Expand the function prologue.  The prologue is responsible for reserving
+   storage for the frame, saving the call-saved registers and loading the
+   PIC register if needed.  */
+
+void
+sparc_expand_prologue (void)
+{
+  int leaf_function_p = current_function_uses_only_leaf_regs;
 
   /* Need to use actual_fsize, since we are also allocating
      space for our callee (and our own register save area).  */
-  actual_fsize = compute_frame_size (size, leaf_function);
+  actual_fsize = sparc_compute_frame_size (get_frame_size(), leaf_function_p);
 
-  if (leaf_function)
+  if (leaf_function_p)
     {
-      frame_base_name = "%sp";
+      frame_base_reg = stack_pointer_rtx;
       frame_base_offset = actual_fsize + SPARC_STACK_BIAS;
     }
   else
     {
-      frame_base_name = "%fp";
+      frame_base_reg = hard_frame_pointer_rtx;
       frame_base_offset = SPARC_STACK_BIAS;
     }
 
-  /* This is only for the human reader.  */
-  fprintf (file, "\t%s#PROLOGUE# 0\n", ASM_COMMENT_START);
-
   if (actual_fsize == 0)
     /* do nothing.  */ ;
-  else if (! leaf_function)
+  else if (leaf_function_p)
     {
       if (actual_fsize <= 4096)
-       fprintf (file, "\tsave\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n",
-                actual_fsize);
+       emit_stack_pointer_increment (GEN_INT (- actual_fsize));
       else if (actual_fsize <= 8192)
        {
-         fprintf (file, "\tsave\t%%sp, -4096, %%sp\n");
-         fprintf (file, "\tadd\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n",
-                  actual_fsize - 4096);
+         emit_stack_pointer_increment (GEN_INT (-4096));
+         emit_stack_pointer_increment (GEN_INT (4096 - actual_fsize));
        }
       else
        {
-         build_big_number (file, -actual_fsize, "%g1");
-         fprintf (file, "\tsave\t%%sp, %%g1, %%sp\n");
+         rtx reg = gen_rtx_REG (Pmode, 1);
+         emit_move_insn (reg, GEN_INT (-actual_fsize));
+         emit_stack_pointer_increment (reg);
        }
     }
-  else /* leaf function */
+  else
     {
       if (actual_fsize <= 4096)
-       fprintf (file, "\tadd\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n",
-                actual_fsize);
+        emit_insn (gen_save_register_window (GEN_INT (-actual_fsize)));
       else if (actual_fsize <= 8192)
        {
-         fprintf (file, "\tadd\t%%sp, -4096, %%sp\n");
-         fprintf (file, "\tadd\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n",
-                  actual_fsize - 4096);
+         emit_insn (gen_save_register_window (GEN_INT (-4096)));
+         emit_stack_pointer_increment (GEN_INT (4096 - actual_fsize));
        }
       else
        {
-         build_big_number (file, -actual_fsize, "%g1");
-         fprintf (file, "\tadd\t%%sp, %%g1, %%sp\n");
+         rtx reg = gen_rtx_REG (Pmode, 1);
+         emit_move_insn (reg, GEN_INT (-actual_fsize));
+         emit_insn (gen_save_register_window (reg));
        }
     }
 
+  /* Call-saved registers are saved just above the outgoing argument area.  */
+  if (num_gfregs)
+    emit_save_regs ();
+
+  /* Load the PIC register if needed.  */
+  if (flag_pic && current_function_uses_pic_offset_table)
+    load_pic_register ();
+}
+/* This function generates the assembly code for function entry, which boils
+   down to emitting the necessary .register directives.  It also informs the
+   DWARF-2 back-end on the layout of the frame.
+
+   ??? Historical cruft: "On SPARC, move-double insns between fpu and cpu need
+   an 8-byte block of memory.  If any fpu reg is used in the function, we
+   allocate such a block here, at the bottom of the frame, just in case it's
+   needed."  Could this explain the -8 in emit_restore_regs?  */
+
+static void
+sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+{
+  int leaf_function_p = current_function_uses_only_leaf_regs;
+
+  sparc_output_scratch_registers (file);
+
   if (dwarf2out_do_frame () && actual_fsize)
     {
       char *label = dwarf2out_cfi_label ();
 
       /* The canonical frame address refers to the top of the frame.  */
-      dwarf2out_def_cfa (label, (leaf_function ? STACK_POINTER_REGNUM
-                                : HARD_FRAME_POINTER_REGNUM),
+      dwarf2out_def_cfa (label,
+                        leaf_function_p
+                        ? STACK_POINTER_REGNUM
+                        : HARD_FRAME_POINTER_REGNUM,
                         frame_base_offset);
 
-      if (! leaf_function)
+      if (! leaf_function_p)
        {
          /* Note the register window save.  This tells the unwinder that
             it needs to restore the window registers from the previous
@@ -4387,225 +4291,215 @@ sparc_nonflat_function_prologue (FILE *file, HOST_WIDE_INT size,
          dwarf2out_return_reg (label, 31);
        }
     }
+}
 
-  /* If doing anything with PIC, do it now.  */
-  if (! flag_pic)
-    fprintf (file, "\t%s#PROLOGUE# 1\n", ASM_COMMENT_START);
+/* Expand the function epilogue, either normal or part of a sibcall.
+   We emit all the instructions except the return or the call.  */
+
+void
+sparc_expand_epilogue (void)
+{
+  int leaf_function_p = current_function_uses_only_leaf_regs;
 
-  /* Call saved registers are saved just above the outgoing argument area.  */
   if (num_gfregs)
-    {
-      HOST_WIDE_INT offset, real_offset;
-      int n_regs;
-      const char *base;
+    emit_restore_regs ();
 
-      real_offset = -apparent_fsize;
-      offset = -apparent_fsize + frame_base_offset;
-      if (offset < -4096 || offset + num_gfregs * 4 > 4096)
+  if (actual_fsize == 0)
+    /* do nothing.  */ ;
+  else if (leaf_function_p)
+    {
+      if (actual_fsize <= 4096)
+       emit_stack_pointer_decrement (GEN_INT (- actual_fsize));
+      else if (actual_fsize <= 8192)
        {
-         /* ??? This might be optimized a little as %g1 might already have a
-            value close enough that a single add insn will do.  */
-         /* ??? Although, all of this is probably only a temporary fix
-            because if %g1 can hold a function result, then
-            output_function_epilogue will lose (the result will get
-            clobbered).  */
-         build_big_number (file, offset, "%g1");
-         fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name);
-         base = "%g1";
-         offset = 0;
+         emit_stack_pointer_decrement (GEN_INT (-4096));
+         emit_stack_pointer_decrement (GEN_INT (4096 - actual_fsize));
        }
       else
        {
-         base = frame_base_name;
+         rtx reg = gen_rtx_REG (Pmode, 1);
+         emit_move_insn (reg, GEN_INT (-actual_fsize));
+         emit_stack_pointer_decrement (reg);
        }
-
-      n_regs = save_regs (file, 0, 8, base, offset, 0, real_offset);
-      save_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs,
-                real_offset);
     }
 }
-
-/* Output code to restore any call saved registers.  */
-
+  
+/* This function generates the assembly code for function exit.  */
+  
 static void
-output_restore_regs (FILE *file, int leaf_function ATTRIBUTE_UNUSED)
+sparc_asm_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
-  HOST_WIDE_INT offset;
-  int n_regs;
-  const char *base;
+  /* If code does not drop into the epilogue, we have to still output
+     a dummy nop for the sake of sane backtraces.  Otherwise, if the
+     last two instructions of a function were "call foo; dslot;" this
+     can make the return PC of foo (ie. address of call instruction
+     plus 8) point to the first instruction in the next function.  */
 
-  offset = -apparent_fsize + frame_base_offset;
-  if (offset < -4096 || offset + num_gfregs * 4 > 4096 - 8 /*double*/)
-    {
-      build_big_number (file, offset, "%g1");
-      fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name);
-      base = "%g1";
-      offset = 0;
-    }
-  else
-    {
-      base = frame_base_name;
-    }
+  rtx insn, last_real_insn;
 
-  n_regs = restore_regs (file, 0, 8, base, offset, 0);
-  restore_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs);
-}
+  insn = get_last_insn ();
 
-/* This function generates the assembly code for function exit,
-   on machines that need it.
+  last_real_insn = prev_real_insn (insn);
+  if (last_real_insn
+      && GET_CODE (last_real_insn) == INSN
+      && GET_CODE (PATTERN (last_real_insn)) == SEQUENCE)
+    last_real_insn = XVECEXP (PATTERN (last_real_insn), 0, 0);
 
-   The function epilogue should not depend on the current stack pointer!
-   It should use the frame pointer only.  This is mandatory because
-   of alloca; we also take advantage of it to omit stack adjustments
-   before returning.  */
+  if (last_real_insn && GET_CODE (last_real_insn) == CALL_INSN)
+    fputs("\tnop\n", file);
 
-static void
-sparc_output_function_epilogue (FILE *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 *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, last_real_insn;
+  if (GET_CODE (pat) != SET)
+    abort ();
 
-      insn = get_last_insn ();
+  operands[0] = SET_DEST (pat);
+  pat = SET_SRC (pat);
 
-      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);
+  switch (GET_CODE (pat))
+    {
+      case PLUS:
+       operands[1] = XEXP (pat, 0);
+       operands[2] = XEXP (pat, 1);
+       output_asm_insn (" restore %r1, %2, %Y0", operands);
+       break;
+      case LO_SUM:
+       operands[1] = XEXP (pat, 0);
+       operands[2] = XEXP (pat, 1);
+       output_asm_insn (" restore %r1, %%lo(%a2), %Y0", operands);
+       break;
+      case ASHIFT:
+       operands[1] = XEXP (pat, 0);
+       if (XEXP (pat, 1) != const1_rtx)
+         abort();
+       output_asm_insn (" restore %r1, %r1, %Y0", operands);
+       break;
+      default:
+       operands[1] = pat;
+       output_asm_insn (" restore %%g0, %1, %Y0", operands);
+       break;
+    }
+}
+  
+/* Output a return.  */
 
-      if (last_real_insn && GET_CODE (last_real_insn) == CALL_INSN)
-       fputs("\tnop\n", file);
+const char *
+output_return (rtx insn)
+{
+  int leaf_function_p = current_function_uses_only_leaf_regs;
+  bool delay_slot_filled_p = dbr_sequence_length () > 0;
+  /* True if the caller has placed an "unimp" insn immediately after the call.
+     This insn is used in the 32-bit ABI when calling a function that returns
+     a non zero-sized structure. The 64-bit ABI doesn't have it.  Be careful
+     to have this test be the same as that used on the call.  */
+  bool sparc_skip_caller_unimp
+    = ! TARGET_ARCH64
+      && current_function_returns_struct
+      && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))
+         == INTEGER_CST)
+      && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl)));
+
+  if (leaf_function_p)
+    {
+      /* This is a leaf function so we don't have to bother restoring the
+        register window, which frees us from dealing with the convoluted
+        semantics of restore/return.  We simply output the jump to the
+        return address and the insn in the delay slot, which usually is
+        the substraction restoring the stack pointer %sp.  */
 
-      if (GET_CODE (insn) == NOTE)
-             insn = prev_nonnote_insn (insn);
-      if (insn && GET_CODE (insn) == BARRIER)
-             goto output_vectors;
-    }
+      if (current_function_calls_eh_return)
+       abort ();
 
-  if (num_gfregs)
-    output_restore_regs (file, leaf_function);
+      fprintf (asm_out_file, "\tjmp\t%%o7+%d\n", sparc_skip_caller_unimp ? 12 : 8);
 
-  /* Work out how to skip the caller's unimp instruction if required.  */
-  if (leaf_function)
-    ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%o7+12" : "retl");
-  else
-    ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%i7+12" : "ret");
+      if (delay_slot_filled_p)
+       {
+         rtx delay = NEXT_INSN (insn);
+         if (! delay)
+           abort ();
 
-  if (! leaf_function)
+         final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
+         PATTERN (delay) = gen_blockage ();
+         INSN_CODE (delay) = -1;
+       }
+      else
+       fputs ("\t nop\n", asm_out_file);
+    }
+  else
     {
+      /* This is a regular function so we have to restore the register window.
+        We may have a pending insn for the delay slot, which will be either
+        combined with the 'restore' instruction or put in the delay slot of
+        the 'return' instruction.  */
+
       if (current_function_calls_eh_return)
        {
-         if (current_function_epilogue_delay_list)
-           abort ();
-         if (SKIP_CALLERS_UNIMP_P)
+         /* If the function uses __builtin_eh_return, the eh_return
+            machinery occupies the delay slot.  */
+         if (delay_slot_filled_p || sparc_skip_caller_unimp)
            abort ();
 
-         fputs ("\trestore\n\tretl\n\tadd\t%sp, %g1, %sp\n", file);
+         if (TARGET_V9)
+           fputs ("\treturn\t%i7+8\n", asm_out_file);
+         else
+           fputs ("\trestore\n\tjmp\t%o7+8\n", asm_out_file);
+
+         fputs ("\t add\t%sp, %g1, %sp\n", asm_out_file);
        }
-      /* If we wound up with things in our delay slot, flush them here.  */
-      else if (current_function_epilogue_delay_list)
+      else if (delay_slot_filled_p)
        {
-         rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0));
+         rtx delay, pat;
 
-         if (TARGET_V9 && ! epilogue_renumber (&delay, 1))
+         delay = NEXT_INSN (insn);
+         if (! delay)
+           abort ();
+
+         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, NULL);
+             epilogue_renumber (&pat, 0);
+             fprintf (asm_out_file, "\treturn\t%%i7+%d\n",
+                      sparc_skip_caller_unimp ? 12 : 8);
+             final_scan_insn (delay, asm_out_file, 1, 0, 0, NULL);
            }
          else
            {
-             rtx insn, src;
-
-             if (GET_CODE (delay) != SET)
-               abort();
-
-             src = SET_SRC (delay);
-             if (GET_CODE (src) == ASHIFT)
-               {
-                 if (XEXP (src, 1) != const1_rtx)
-                   abort();
-                 SET_SRC (delay)
-                   = gen_rtx_PLUS (GET_MODE (src), XEXP (src, 0),
-                                   XEXP (src, 0));
-               }
-
-             insn = gen_rtx_PARALLEL (VOIDmode,
-                                      gen_rtvec (2, delay,
-                                                 gen_rtx_RETURN (VOIDmode)));
-             insn = emit_jump_insn (insn);
-
-             sparc_emitting_epilogue = true;
-             final_scan_insn (insn, file, 1, 0, 1, NULL);
-             sparc_emitting_epilogue = false;
+             fprintf (asm_out_file, "\tjmp\t%%i7+%d\n",
+                      sparc_skip_caller_unimp ? 12 : 8);
+             output_restore (pat);
            }
+
+         PATTERN (delay) = gen_blockage ();
+         INSN_CODE (delay) = -1;
        }
-      else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P)
-       fputs ("\treturn\t%i7+8\n\tnop\n", file);
       else
-       fprintf (file, "\t%s\n\trestore\n", ret);
-    }
-  /* 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, NULL);
-    }
-  /* 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, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n",
-            ret, actual_fsize);
-  else if (actual_fsize <= 8192)
-    fprintf (file, "\tsub\t%%sp, -4096, %%sp\n\t%s\n\tsub\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n",
-            ret, actual_fsize - 4096);
-  else
-    {
-      build_big_number (file, actual_fsize, "%g1");
-      fprintf (file, "\t%s\n\tadd\t%%sp, %%g1, %%sp\n", ret);
+        {
+         /* The delay slot is empty.  */
+         if (TARGET_V9)
+           fprintf (asm_out_file, "\treturn\t%%i7+%d\n\t nop\n",
+                    sparc_skip_caller_unimp ? 12 : 8);
+         else
+           fprintf (asm_out_file, "\tjmp\t%%i7+%d\n\t restore\n",
+                    sparc_skip_caller_unimp ? 12 : 8);
+       }
     }
 
- output_vectors:
-  sparc_output_deferred_case_vectors ();
+  return "";
 }
 
 /* Output a sibling call.  */
@@ -4613,144 +4507,76 @@ sparc_nonflat_function_epilogue (FILE *file,
 const char *
 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;
-
-  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);
-
-         if (! delay)
-           abort ();
-
-         final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
-         PATTERN (delay) = gen_blockage ();
-         INSN_CODE (delay) = -1;
-         delay_slot = 0;
-       }
-      output_restore_regs (asm_out_file, leaf_regs);
-    }
+  int leaf_function_p = current_function_uses_only_leaf_regs;
+  bool delay_slot_filled_p = dbr_sequence_length () > 0;
+  rtx operands[1];
 
   operands[0] = call_operand;
 
-  if (leaf_regs)
+  if (leaf_function_p)
     {
-#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
-      HOST_WIDE_INT size = 0;
+      /* This is a leaf function so we don't have to bother restoring the
+        register window.  We simply output the jump to the function and
+        the insn in the delay slot (if any).  */
 
-      if ((actual_fsize || ! spare_slot) && delay_slot)
+      if (LEAF_SIBCALL_SLOT_RESERVED_P && delay_slot_filled_p)
+       abort();
+
+      if (delay_slot_filled_p)
        {
          rtx delay = NEXT_INSN (insn);
-
          if (! delay)
            abort ();
 
-         final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
+         output_asm_insn ("sethi\t%%hi(%a0), %%g1", operands);
+         output_asm_insn ("jmp\t%%g1 + %%lo(%a0)", operands);
+         final_scan_insn (delay, asm_out_file, 1, 0, 0, NULL);
+
          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
-           {
-             build_big_number (asm_out_file, actual_fsize, "%g1");
-             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, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n", size);
-         else if (! delay_slot)
-           fputs ("\t nop\n", asm_out_file);
        }
       else
        {
-         if (size)
-           fprintf (asm_out_file, "\tsub\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n", size);
          /* Use or with rs2 %%g0 instead of mov, so that as/ld can optimize
             it into branch if possible.  */
          output_asm_insn ("or\t%%o7, %%g0, %%g1", operands);
          output_asm_insn ("call\t%a0, 0", operands);
          output_asm_insn (" or\t%%g1, %%g0, %%o7", operands);
        }
-      return "";
     }
-
-  output_asm_insn ("call\t%a0, 0", operands);
-  if (delay_slot)
+  else
     {
-      rtx delay = NEXT_INSN (insn), pat;
-
-      if (! delay)
-       abort ();
+      /* 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.  */
 
-      pat = PATTERN (delay);
-      if (GET_CODE (pat) != SET)
-       abort ();
+      output_asm_insn ("call\t%a0, 0", operands);
 
-      operands[0] = SET_DEST (pat);
-      pat = SET_SRC (pat);
-      switch (GET_CODE (pat))
+      if (delay_slot_filled_p)
        {
-       case PLUS:
-         operands[1] = XEXP (pat, 0);
-         operands[2] = XEXP (pat, 1);
-         output_asm_insn (" restore %r1, %2, %Y0", operands);
-         break;
-       case LO_SUM:
-         operands[1] = XEXP (pat, 0);
-         operands[2] = XEXP (pat, 1);
-         output_asm_insn (" restore %r1, %%lo(%a2), %Y0", operands);
-         break;
-       case ASHIFT:
-         operands[1] = XEXP (pat, 0);
-         output_asm_insn (" restore %r1, %r1, %Y0", operands);
-         break;
-       default:
-         operands[1] = pat;
-         output_asm_insn (" restore %%g0, %1, %Y0", operands);
-         break;
+         rtx delay = NEXT_INSN (insn);
+         if (! delay)
+           abort ();
+
+         output_restore (PATTERN (delay));
+
+         PATTERN (delay) = gen_blockage ();
+         INSN_CODE (delay) = -1;
        }
-      PATTERN (delay) = gen_blockage ();
-      INSN_CODE (delay) = -1;
+      else
+       output_restore (NULL_RTX);
     }
-  else
-    fputs ("\t restore\n", asm_out_file);
+
   return "";
 }
 \f
 /* Functions for handling argument passing.
 
-   For v8 the first six args are normally in registers and the rest are
+   For 32-bit, the first 6 args are normally in registers and the rest are
    pushed.  Any arg that starts within the first 6 words is at least
    partially passed in a register unless its data type forbids.
 
-   For v9, the argument registers are laid out as an array of 16 elements
+   For 64-bit, the argument registers are laid out as an array of 16 elements
    and arguments are added sequentially.  The first 6 int args and up to the
    first 16 fp args (depending on size) are passed in regs.
 
@@ -4775,7 +4601,7 @@ output_sibcall (rtx insn, rtx 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.
@@ -4792,7 +4618,81 @@ output_sibcall (rtx insn, rtx call_operand)
      appropriate integer reg and the appropriate fp reg.
      If the value is not one of the first 6 arguments the value is passed in
      the appropriate fp reg and in memory.
-   */
+
+
+   Summary of the calling conventions implemented by GCC on SPARC:
+
+   32-bit ABI:
+                                size      argument     return value
+
+      small integer              <4       int. reg.      int. reg.
+      word                        4       int. reg.      int. reg.
+      double word                 8       int. reg.      int. reg.
+
+      _Complex small integer     <8       int. reg.      int. reg.
+      _Complex word               8       int. reg.      int. reg.
+      _Complex double word       16        memory        int. reg.
+
+      vector integer            <=8       int. reg.       FP reg.
+      vector integer             >8        memory         memory
+
+      float                       4       int. reg.       FP reg.
+      double                      8       int. reg.       FP reg.
+      long double                16        memory         memory
+
+      _Complex float              8        memory         FP reg.
+      _Complex double            16        memory         FP reg.
+      _Complex long double       32        memory         FP reg.
+
+      vector float             <=32        memory         FP reg.
+      vector float              >32        memory         memory
+
+      aggregate                 any        memory         memory
+
+
+
+    64-bit ABI:
+                                size      argument     return value
+
+      small integer              <8       int. reg.      int. reg.
+      word                        8       int. reg.      int. reg.
+      double word                16       int. reg.      int. reg.
+
+      _Complex small integer    <16       int. reg.      int. reg.
+      _Complex word              16       int. reg.      int. reg.
+      _Complex double word       32        memory        int. reg.
+
+      vector integer           <=16        FP reg.        FP reg.
+      vector integer       16<s<=32        memory         FP reg.
+      vector integer            >32        memory         memory
+
+      float                       4        FP reg.        FP reg.
+      double                      8        FP reg.        FP reg.
+      long double                16        FP reg.        FP reg.
+
+      _Complex float              8        FP reg.        FP reg.
+      _Complex double            16        FP reg.        FP reg.
+      _Complex long double       32        memory         FP reg.
+
+      vector float             <=16        FP reg.        FP reg.
+      vector float         16<s<=32        memory         FP reg.
+      vector float              >32        memory         memory
+
+      aggregate                <=16         reg.           reg.
+      aggregate            16<s<=32        memory          reg.
+      aggregate                 >32        memory         memory
+
+
+
+Note #1: complex floating-point types follow the extended SPARC ABIs as
+implemented by the Sun compiler.
+
+Note #2: integral vector types follow the scalar floating-point types
+conventions to match what is implemented by the Sun VIS SDK.
+
+Note #3: floating-point vector types follow the complex floating-point
+types conventions.  */
+
 
 /* Maximum number of int regs for args.  */
 #define SPARC_INT_ARG_MAX 6
@@ -4816,8 +4716,56 @@ init_cumulative_args (struct sparc_args *cum, tree fntype,
   cum->libcall_p = fntype == 0;
 }
 
+/* Handle the TARGET_PROMOTE_PROTOTYPES target hook.
+   When a prototype says `char' or `short', really pass an `int'.  */
+
+static bool
+sparc_promote_prototypes (tree fntype ATTRIBUTE_UNUSED)
+{
+  return TARGET_ARCH32 ? true : false;
+}
+
+/* Handle the TARGET_STRICT_ARGUMENT_NAMING target hook.  */
+
+static bool
+sparc_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED)
+{
+  return TARGET_ARCH64 ? true : false;
+}
+
+/* Scan the record type TYPE and return the following predicates:
+    - INTREGS_P: the record contains at least one field or sub-field
+      that is eligible for promotion in integer registers.
+    - FP_REGS_P: the record contains at least one field or sub-field
+      that is eligible for promotion in floating-point registers.
+    - PACKED_P: the record contains at least one field that is packed.
+
+   Sub-fields are not taken into account for the PACKED_P predicate.  */
+
+static void
+scan_record_type (tree type, int *intregs_p, int *fpregs_p, int *packed_p)
+{
+  tree field;
+
+  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+    {
+      if (TREE_CODE (field) == FIELD_DECL)
+       {
+         if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
+           scan_record_type (TREE_TYPE (field), intregs_p, fpregs_p, 0);
+         else if (FLOAT_TYPE_P (TREE_TYPE (field)) && TARGET_FPU)
+           *fpregs_p = 1;
+         else
+           *intregs_p = 1;
+
+         if (packed_p && DECL_PACKED (field))
+           *packed_p = 1;
+       }
+    }
+}
+
 /* Compute the slot number to pass an argument in.
-   Returns the slot number or -1 if passing on the stack.
+   Return the slot number or -1 if passing on the stack.
 
    CUM is a variable of type CUMULATIVE_ARGS which gives info about
     the preceding args and about the function being called.
@@ -4844,109 +4792,90 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
 
   *ppadding = 0;
 
-  if (type != 0 && TREE_ADDRESSABLE (type))
+  if (type && TREE_ADDRESSABLE (type))
     return -1;
+
   if (TARGET_ARCH32
-      && type != 0 && mode == BLKmode
+      && mode == BLKmode
+      && type
       && TYPE_ALIGN (type) % PARM_BOUNDARY != 0)
     return -1;
 
-  switch (mode)
+  /* For SPARC64, objects requiring 16-byte alignment get it.  */
+  if (TARGET_ARCH64
+      && GET_MODE_ALIGNMENT (mode) >= 2 * BITS_PER_WORD
+      && (slotno & 1) != 0)
+    slotno++, *ppadding = 1;
+
+  switch (GET_MODE_CLASS (mode))
     {
-    case VOIDmode :
-      /* MODE is VOIDmode when generating the actual call.
-        See emit_call_1.  */
-      return -1;
+    case MODE_FLOAT:
+    case MODE_COMPLEX_FLOAT:
+    case MODE_VECTOR_INT:
+    case MODE_VECTOR_FLOAT:
+      if (TARGET_ARCH64 && TARGET_FPU && named)
+       {
+         if (slotno >= SPARC_FP_ARG_MAX)
+           return -1;
+         regno = SPARC_FP_ARG_FIRST + slotno * 2;
+         /* Arguments filling only one single FP register are
+            right-justified in the outer double FP register.  */
+         if (GET_MODE_SIZE (mode) <= 4)
+           regno++;
+         break;
+       }
+      /* fallthrough */
 
-    case QImode : case CQImode :
-    case HImode : case CHImode :
-    case SImode : case CSImode :
-    case DImode : case CDImode :
-    case TImode : case CTImode :
+    case MODE_INT:
+    case MODE_COMPLEX_INT:
       if (slotno >= SPARC_INT_ARG_MAX)
        return -1;
       regno = regbase + slotno;
       break;
 
-    case SFmode : case SCmode :
-    case DFmode : case DCmode :
-    case TFmode : case TCmode :
-      if (TARGET_ARCH32)
-       {
-         if (slotno >= SPARC_INT_ARG_MAX)
-           return -1;
-         regno = regbase + slotno;
-       }
-      else
-       {
-         if ((mode == TFmode || mode == TCmode)
-             && (slotno & 1) != 0)
-           slotno++, *ppadding = 1;
-         if (TARGET_FPU && named)
-           {
-             if (slotno >= SPARC_FP_ARG_MAX)
-               return -1;
-             regno = SPARC_FP_ARG_FIRST + slotno * 2;
-             if (mode == SFmode)
-               regno++;
-           }
-         else
-           {
-             if (slotno >= SPARC_INT_ARG_MAX)
-               return -1;
-             regno = regbase + slotno;
-           }
-       }
-      break;
+    case MODE_RANDOM:
+      if (mode == VOIDmode)
+       /* MODE is VOIDmode when generating the actual call.  */
+       return -1;
 
-    case BLKmode :
-      /* For sparc64, objects requiring 16 byte alignment get it.  */
-      if (TARGET_ARCH64)
-       {
-         if (type && TYPE_ALIGN (type) == 128 && (slotno & 1) != 0)
-           slotno++, *ppadding = 1;
-       }
+      if (mode != BLKmode)
+       abort ();
+
+      /* For SPARC64, objects requiring 16-byte alignment get it.  */
+      if (TARGET_ARCH64
+         && type
+         && TYPE_ALIGN (type) >= 2 * BITS_PER_WORD
+         && (slotno & 1) != 0)
+       slotno++, *ppadding = 1;
 
-      if (TARGET_ARCH32
-         || (type && TREE_CODE (type) == UNION_TYPE))
+      if (TARGET_ARCH32 || (type && TREE_CODE (type) == UNION_TYPE))
        {
          if (slotno >= SPARC_INT_ARG_MAX)
            return -1;
          regno = regbase + slotno;
        }
-      else
+      else  /* TARGET_ARCH64 && type && TREE_CODE (type) == RECORD_TYPE */
        {
-         tree field;
-         int intregs_p = 0, fpregs_p = 0;
-         /* The ABI obviously doesn't specify how packed
-            structures are passed.  These are defined to be passed
-            in int regs if possible, otherwise memory.  */
-         int packed_p = 0;
-
-         /* First see what kinds of registers we need.  */
-         for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
-           {
-             if (TREE_CODE (field) == FIELD_DECL)
-               {
-                 if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
-                     && TARGET_FPU)
-                   fpregs_p = 1;
-                 else
-                   intregs_p = 1;
-                 if (DECL_PACKED (field))
-                   packed_p = 1;
-               }
-           }
+         int intregs_p = 0, fpregs_p = 0, packed_p = 0;
+
+         /* First see what kinds of registers we would need.  */
+         scan_record_type (type, &intregs_p, &fpregs_p, &packed_p);
+
+         /* The ABI obviously doesn't specify how packed structures
+            are passed.  These are defined to be passed in int regs
+            if possible, otherwise memory.  */
          if (packed_p || !named)
            fpregs_p = 0, intregs_p = 1;
 
          /* If all arg slots are filled, then must pass on stack.  */
          if (fpregs_p && slotno >= SPARC_FP_ARG_MAX)
            return -1;
+
          /* If there are only int args and all int arg slots are filled,
             then must pass on stack.  */
          if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX)
            return -1;
+
          /* Note that even if all int arg slots are filled, fp members may
             still be passed in regs if such regs are available.
             *PREGNO isn't set because there may be more than one, it's up
@@ -4972,7 +4901,7 @@ struct function_arg_record_value_parms
   int named;           /* whether the argument is named.  */
   int regbase;         /* regno of the base register.  */
   int stack;           /* 1 if part of the argument is on the stack.  */
-  int intoffset;       /* offset of the pending integer field.  */
+  int intoffset;       /* offset of the first pending integer field.  */
   unsigned int nregs;  /* number of words passed in registers.  */
 };
 
@@ -4983,6 +4912,7 @@ static void function_arg_record_value_2
 static void function_arg_record_value_1
  (tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
 static rtx function_arg_record_value (tree, enum machine_mode, int, int, int);
+static rtx function_arg_union_value (int, enum machine_mode, int);
 
 /* A subroutine of function_arg_record_value.  Traverse the structure
    recursively and determine how many registers will be required.  */
@@ -5029,20 +4959,21 @@ function_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos,
                                         bitpos,
                                         parms,
                                         packed_p);
-         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)
+         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;
 
@@ -5121,6 +5052,7 @@ function_arg_record_value_3 (HOST_WIDE_INT bitpos,
 
       this_slotno += 1;
       intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1;
+      mode = word_mode;
       parms->nregs += 1;
       intslots -= 1;
     }
@@ -5166,13 +5098,11 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
                                         bitpos,
                                         parms,
                                         packed_p);
-         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)
+         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;
@@ -5180,9 +5110,6 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
              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;
@@ -5190,6 +5117,9 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
                case TCmode: mode = TFmode; break;
                default: break;
                }
+             regno = SPARC_FP_ARG_FIRST + this_slotno * 2;
+             if (GET_MODE_SIZE (mode) <= 4 && (bitpos & 32) != 0)
+               regno++;
              reg = gen_rtx_REG (mode, regno);
              XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
                = gen_rtx_EXPR_LIST (VOIDmode, reg,
@@ -5248,6 +5178,7 @@ function_arg_record_value (tree type, enum machine_mode mode,
   parms.intoffset = 0;
   function_arg_record_value_1 (type, 0, &parms, false);
 
+  /* Take into account pending integer fields.  */
   if (parms.intoffset != -1)
     {
       unsigned int startbit, endbit;
@@ -5317,6 +5248,33 @@ function_arg_record_value (tree type, enum machine_mode mode,
   return parms.ret;
 }
 
+/* Used by function_arg and function_value to implement the conventions
+   of the 64-bit ABI for passing and returning unions.
+   Return an expression valid as a return value for the two macros
+   FUNCTION_ARG and FUNCTION_VALUE.
+
+   SIZE is the size in bytes of the union.
+   MODE is the argument's machine mode.
+   REGNO is the hard register the union will be passed in.  */
+
+static rtx
+function_arg_union_value (int size, enum machine_mode mode, int regno)
+{
+  int nwords = ROUND_ADVANCE (size), i;
+  rtx regs;
+
+  /* Unions are passed left-justified.  */
+  regs = gen_rtx_PARALLEL (mode, rtvec_alloc (nwords));
+
+  for (i = 0; i < nwords; i++)
+    XVECEXP (regs, 0, i)
+      = gen_rtx_EXPR_LIST (VOIDmode,
+                          gen_rtx_REG (word_mode, regno + i),
+                          GEN_INT (UNITS_PER_WORD * i));
+
+  return regs;
+}
+
 /* Handle the FUNCTION_ARG macro.
    Determine where to put an argument to a function.
    Value is zero to push the argument on the stack,
@@ -5366,21 +5324,21 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
     }
   else if (type && TREE_CODE (type) == UNION_TYPE)
     {
-      enum machine_mode mode;
-      int bytes = int_size_in_bytes (type);
+      HOST_WIDE_INT size = int_size_in_bytes (type);
 
-      if (bytes > 16)
-       abort ();
+      if (size > 16)
+       abort (); /* shouldn't get here */
 
-      mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
-      reg = gen_rtx_REG (mode, regno);
+      return function_arg_union_value (size, mode, regno);
     }
   /* v9 fp args in reg slots beyond the int reg slots get passed in regs
      but also have the slot allocated for them.
      If no prototype is in scope fp values in register slots get passed
      in two places, either fp regs and int regs or fp regs and memory.  */
   else if ((GET_MODE_CLASS (mode) == MODE_FLOAT
-           || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
+           || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
       && SPARC_FP_REG_P (regno))
     {
       reg = gen_rtx_REG (mode, regno);
@@ -5481,20 +5439,20 @@ function_arg_partial_nregs (const struct sparc_args *cum,
       if ((slotno + (mode == BLKmode
                     ? ROUND_ADVANCE (int_size_in_bytes (type))
                     : ROUND_ADVANCE (GET_MODE_SIZE (mode))))
-         > NPARM_REGS (SImode))
-       return NPARM_REGS (SImode) - slotno;
-      return 0;
+         > SPARC_INT_ARG_MAX)
+       return SPARC_INT_ARG_MAX - slotno;
     }
   else
     {
+      /* We are guaranteed by function_arg_pass_by_reference that the size
+        of the argument is not greater than 16 bytes, so we only need to
+        return 1 if the argument is partially passed in registers.  */
+
       if (type && AGGREGATE_TYPE_P (type))
        {
          int size = int_size_in_bytes (type);
-         int align = TYPE_ALIGN (type);
 
-         if (align == 16)
-           slotno += slotno & 1;
-         if (size > 8 && size <= 16
+         if (size > UNITS_PER_WORD
              && slotno == SPARC_INT_ARG_MAX - 1)
            return 1;
        }
@@ -5503,33 +5461,19 @@ function_arg_partial_nregs (const struct sparc_args *cum,
                   && ! (TARGET_FPU && named)))
        {
          /* The complex types are passed as packed types.  */
-         if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
-           return 0;
-
-         if (GET_MODE_ALIGNMENT (mode) == 128)
-           {
-             slotno += slotno & 1;
-
-             /* ??? The mode needs 3 slots?  */
-             if (slotno == SPARC_INT_ARG_MAX - 2)
-               return 1;
-           }
-         else
-           {
-             if (slotno == SPARC_INT_ARG_MAX - 1)
-               return 1;
-           }
+         if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
+             && slotno == SPARC_INT_ARG_MAX - 1)
+           return 1;
        }
       else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
        {
-         if (GET_MODE_ALIGNMENT (mode) == 128)
-           slotno += slotno & 1;
          if ((slotno + GET_MODE_SIZE (mode) / UNITS_PER_WORD)
              > SPARC_FP_ARG_MAX)
            return 1;
        }
-      return 0;
     }
+
+  return 0;
 }
 
 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
@@ -5546,17 +5490,23 @@ function_arg_pass_by_reference (const struct sparc_args *cum ATTRIBUTE_UNUSED,
   if (TARGET_ARCH32)
     {
       return ((type && AGGREGATE_TYPE_P (type))
-             || mode == TFmode || mode == TCmode);
+             /* Extended ABI (as implemented by the Sun compiler) says
+                that all complex floats are passed in memory.  */
+             || mode == SCmode
+             /* Enforce the 2-word cap for passing arguments in registers.
+                This affects CDImode, TFmode, DCmode, TCmode and large
+                vector modes.  */
+             || GET_MODE_SIZE (mode) > 8);
     }
   else
     {
       return ((type && TREE_CODE (type) == ARRAY_TYPE)
-             /* Consider complex values as aggregates, so care
-                for CTImode and TCmode.  */
-             || GET_MODE_SIZE (mode) > 16
              || (type
                  && AGGREGATE_TYPE_P (type)
-                 && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16));
+                 && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)
+             /* Enforce the 2-word cap for passing arguments in registers.
+                This affects CTImode, TCmode and large vector modes.  */
+             || GET_MODE_SIZE (mode) > 16);
     }
 }
 
@@ -5620,17 +5570,70 @@ function_arg_padding (enum machine_mode mode, tree type)
   return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
 }
 
+/* Handle the TARGET_RETURN_IN_MEMORY target hook.
+   Specify whether to return the return value in memory.  */
+
+static bool
+sparc_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+{
+  if (TARGET_ARCH32)
+    /* Original SPARC 32-bit ABI says that quad-precision floats
+       and all structures are returned in memory.  Extended ABI
+       (as implemented by the Sun compiler) says that all complex
+       floats are returned in registers (8 FP registers at most
+       for '_Complex long double').  Return all complex integers
+       in registers (4 at most for '_Complex long long').  */
+    return (TYPE_MODE (type) == BLKmode
+           || TYPE_MODE (type) == TFmode
+           /* Integral vector types follow the scalar FP types conventions.  */
+           || (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_VECTOR_INT
+               && GET_MODE_SIZE (TYPE_MODE (type)) > 8)
+           /* FP vector types follow the complex FP types conventions.  */
+           || (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_VECTOR_FLOAT
+               && GET_MODE_SIZE (TYPE_MODE (type)) > 32));
+  else
+    /* Original SPARC 64-bit ABI says that structures and unions
+       smaller than 32 bytes are returned in registers.  Extended
+       ABI (as implemented by the Sun compiler) says that all complex
+       floats are returned in registers (8 FP registers at most
+       for '_Complex long double').  Return all complex integers
+       in registers (4 at most for '_Complex TItype').  */
+    return ((TYPE_MODE (type) == BLKmode
+            && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32)
+           || GET_MODE_SIZE (TYPE_MODE (type)) > 32);
+}
+
+/* Handle the TARGET_STRUCT_VALUE target hook.
+   Return where to find the structure return value address.  */
+
+static rtx
+sparc_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED, int incoming)
+{
+  if (TARGET_ARCH64)
+    return 0;
+  else
+    {
+      if (incoming)
+       return gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx,
+                                                 STRUCT_VALUE_OFFSET));
+      else
+       return gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
+                                                 STRUCT_VALUE_OFFSET));
+    }
+}
+
 /* Handle FUNCTION_VALUE, FUNCTION_OUTGOING_VALUE, and LIBCALL_VALUE macros.
    For v9, function return values are subject to the same rules as arguments,
-   except that up to 32-bytes may be returned in registers.  */
+   except that up to 32 bytes may be returned in registers.  */
 
 rtx
 function_value (tree type, enum machine_mode mode, int incoming_p)
 {
-  int regno;
+  /* Beware that the two values are swapped here wrt function_arg.  */
   int regbase = (incoming_p
                 ? SPARC_OUTGOING_INT_ARG_FIRST
                 : SPARC_INCOMING_INT_ARG_FIRST);
+  int regno;
 
   if (TARGET_ARCH64 && type)
     {
@@ -5644,6 +5647,15 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
 
          return function_arg_record_value (type, mode, 0, 1, regbase);
        }
+      else if (TREE_CODE (type) == UNION_TYPE)
+       {
+         HOST_WIDE_INT size = int_size_in_bytes (type);
+
+         if (size > 32)
+           abort (); /* shouldn't get here */
+
+         return function_arg_union_value (size, mode, regbase);
+       }
       else if (AGGREGATE_TYPE_P (type))
        {
          /* All other aggregate types are passed in an integer register
@@ -5651,22 +5663,19 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
          HOST_WIDE_INT bytes = int_size_in_bytes (type);
 
          if (bytes > 32)
-           abort ();
+           abort (); /* shouldn't get here */
 
          mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
        }
+      else if (GET_MODE_CLASS (mode) == MODE_INT
+              && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+       mode = word_mode;
     }
-    
-  if (TARGET_ARCH64
-      && GET_MODE_CLASS (mode) == MODE_INT 
-      && GET_MODE_SIZE (mode) < UNITS_PER_WORD
-      && type && ! AGGREGATE_TYPE_P (type))
-    mode = DImode;
 
-  if (incoming_p)
-    regno = BASE_RETURN_VALUE_REG (mode);
+  if (TARGET_FPU && (FLOAT_MODE_P (mode) || VECTOR_MODE_P (mode)))
+    regno = SPARC_FP_ARG_FIRST;
   else
-    regno = BASE_OUTGOING_VALUE_REG (mode);
+    regno = regbase;
 
   return gen_rtx_REG (mode, regno);
 }
@@ -5675,14 +5684,14 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
    to determine if stdarg or varargs is used and return the address of
    the first unnamed parameter.  */
 
-rtx
+static rtx
 sparc_builtin_saveregs (void)
 {
   int first_reg = current_function_args_info.words;
   rtx address;
   int regno;
 
-  for (regno = first_reg; regno < NPARM_REGS (word_mode); regno++)
+  for (regno = first_reg; regno < SPARC_INT_ARG_MAX; regno++)
     emit_move_insn (gen_rtx_MEM (word_mode,
                                 gen_rtx_PLUS (Pmode,
                                               frame_pointer_rtx,
@@ -5690,7 +5699,7 @@ sparc_builtin_saveregs (void)
                                                        + (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,
@@ -5700,7 +5709,7 @@ sparc_builtin_saveregs (void)
   return address;
 }
 
-/* Implement `va_start' for varargs and stdarg.  */
+/* Implement `va_start' for stdarg.  */
 
 void
 sparc_va_start (tree valist, rtx nextarg)
@@ -5709,119 +5718,96 @@ sparc_va_start (tree valist, rtx nextarg)
   std_expand_builtin_va_start (valist, nextarg);
 }
 
-/* Implement `va_arg'.  */
+/* Implement `va_arg' for stdarg.  */
 
-rtx
-sparc_va_arg (tree valist, tree type)
+tree
+sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
 {
   HOST_WIDE_INT size, rsize, align;
   tree addr, incr;
-  rtx addr_rtx;
-  int indirect = 0;
-
-  /* Round up sizeof(type) to a word.  */
-  size = int_size_in_bytes (type);
-  rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
-  align = 0;
+  bool indirect;
+  tree ptrtype = build_pointer_type (type);
 
-  if (TARGET_ARCH64)
+  if (function_arg_pass_by_reference (0, TYPE_MODE (type), type, 0))
     {
-      if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD)
-       align = 2 * UNITS_PER_WORD;
-
-      /* Consider complex values as aggregates, so care
-        for CTImode and TCmode.  */
-      if ((unsigned HOST_WIDE_INT) size > 16)
-       {
-         indirect = 1;
-         size = rsize = UNITS_PER_WORD;
-         align = 0;
-       }
-      else if (AGGREGATE_TYPE_P (type))
-       {
-         /* SPARC-V9 ABI states that structures up to 16 bytes in size
-            are given whole slots as needed.  */
-         if (size == 0)
-           size = rsize = UNITS_PER_WORD;
-         else
-           size = rsize;
-       }
+      indirect = true;
+      size = rsize = UNITS_PER_WORD;
+      align = 0;
     }
   else
     {
-      if (AGGREGATE_TYPE_P (type)
-         || TYPE_MODE (type) == TFmode
-         || TYPE_MODE (type) == TCmode)
+      indirect = false;
+      size = int_size_in_bytes (type);
+      rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
+      align = 0;
+    
+      if (TARGET_ARCH64)
        {
-         indirect = 1;
-         size = rsize = UNITS_PER_WORD;
+         /* For SPARC64, objects requiring 16-byte alignment get it.  */
+         if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD)
+           align = 2 * UNITS_PER_WORD;
+
+         /* SPARC-V9 ABI states that structures up to 16 bytes in size
+            are given whole slots as needed.  */
+         if (AGGREGATE_TYPE_P (type))
+           {
+             if (size == 0)
+               size = rsize = UNITS_PER_WORD;
+             else
+               size = rsize;
+           }
        }
     }
 
   incr = valist;
   if (align)
     {
-      incr = fold (build (PLUS_EXPR, ptr_type_node, incr,
-                        build_int_2 (align - 1, 0)));
-      incr = fold (build (BIT_AND_EXPR, ptr_type_node, incr,
-                         build_int_2 (-align, -1)));
+      incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr,
+                          ssize_int (align - 1)));
+      incr = fold (build2 (BIT_AND_EXPR, ptr_type_node, incr,
+                          ssize_int (-align)));
     }
 
-  addr = incr = save_expr (incr);
+  gimplify_expr (&incr, pre_p, post_p, is_gimple_val, fb_rvalue);
+  addr = incr;
+
   if (BYTES_BIG_ENDIAN && size < rsize)
+    addr = fold (build2 (PLUS_EXPR, ptr_type_node, incr,
+                        ssize_int (rsize - size)));
+
+  if (indirect)
     {
-      addr = fold (build (PLUS_EXPR, ptr_type_node, incr,
-                         build_int_2 (rsize - size, 0)));
+      addr = fold_convert (build_pointer_type (ptrtype), addr);
+      addr = build_fold_indirect_ref (addr);
     }
-  incr = fold (build (PLUS_EXPR, ptr_type_node, incr,
-                     build_int_2 (rsize, 0)));
-
-  incr = build (MODIFY_EXPR, ptr_type_node, valist, incr);
-  TREE_SIDE_EFFECTS (incr) = 1;
-  expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
-  addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL);
-
   /* If the address isn't aligned properly for the type,
      we may need to copy to a temporary.  
      FIXME: This is inefficient.  Usually we can do this
      in registers.  */
-  if (align == 0
-      && TYPE_ALIGN (type) > BITS_PER_WORD
-      && !indirect)
-    {
-      /* FIXME: We really need to specify that the temporary is live
-        for the whole function because expand_builtin_va_arg wants
-        the alias set to be get_varargs_alias_set (), but in this
-        case the alias set is that for TYPE and if the memory gets
-        reused it will be reused with alias set TYPE.  */
-      rtx tmp = assign_temp (type, 0, 1, 0);
-      rtx dest_addr;
-
-      addr_rtx = force_reg (Pmode, addr_rtx);
-      addr_rtx = gen_rtx_MEM (BLKmode, addr_rtx);
-      set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
-      set_mem_align (addr_rtx, BITS_PER_WORD);
-      tmp = shallow_copy_rtx (tmp);
-      PUT_MODE (tmp, BLKmode);
-      set_mem_alias_set (tmp, 0);
-      
-      dest_addr = emit_block_move (tmp, addr_rtx, GEN_INT (rsize),
-                                  BLOCK_OP_NORMAL);
-      if (dest_addr != NULL_RTX)
-       addr_rtx = dest_addr;
-      else
-       addr_rtx = XCEXP (tmp, 0, MEM);
-    }
-
-  if (indirect)
+  else if (align == 0
+          && TYPE_ALIGN (type) > BITS_PER_WORD)
     {
-      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 ());
+      tree tmp = create_tmp_var (type, "va_arg_tmp");
+      tree dest_addr = build_fold_addr_expr (tmp);
+
+      tree copy = build_function_call_expr
+       (implicit_built_in_decls[BUILT_IN_MEMCPY],
+        tree_cons (NULL_TREE, dest_addr,
+                   tree_cons (NULL_TREE, addr,
+                              tree_cons (NULL_TREE, size_int (rsize),
+                                         NULL_TREE))));
+
+      gimplify_and_add (copy, pre_p);
+      addr = dest_addr;
     }
+  else
+    addr = fold_convert (ptrtype, addr);
+
+  incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr, ssize_int (rsize)));
+  incr = build2 (MODIFY_EXPR, ptr_type_node, valist, incr);
+  gimplify_and_add (incr, post_p);
 
-  return addr_rtx;
+  return build_fold_indirect_ref (addr);
 }
 \f
 /* Return the string to output a conditional branch to LABEL, which is
@@ -5837,11 +5823,11 @@ sparc_va_arg (tree valist, tree type)
 
    INSN, if set, is the insn.  */
 
-char *
+const char *
 output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
                int noop, rtx insn)
 {
-  static char string[50];
+  static char string[64];
   enum rtx_code code = GET_CODE (op);
   rtx cc_reg = XEXP (op, 0);
   enum machine_mode mode = GET_MODE (cc_reg);
@@ -5857,7 +5843,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
      to
 
      be,pn %xcc, .+12
-     nop
+      nop
      ba .LC30
 
      and
@@ -5867,7 +5853,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
      to
 
      fbe,pt %fcc2, .+16
-     nop
+      nop
      ba .LC29  */
 
   far = get_attr_length (insn) >= 3;
@@ -6060,10 +6046,10 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
   p = strchr (p, '\0');
   if (far)
     {
-      strcpy (p, ".+12\n\tnop\n\tb\t");
+      strcpy (p, ".+12\n\t nop\n\tb\t");
       if (annul || noop)
         p[3] = '6';
-      p += 13;
+      p += 14;
     }
   *p++ = '%';
   *p++ = 'l';
@@ -6072,7 +6058,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
   *p++ = label + '0';
   *p = '\0';
   if (noop)
-    strcpy (p, "\n\tnop");
+    strcpy (p, "\n\t nop");
 
   return string;
 }
@@ -6216,37 +6202,76 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
     }
 }
 
-/* Generate an unsigned DImode to FP conversion.  This is the same code
+/* 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 (rtx *operands, enum machine_mode mode)
+{
+  rtx neglab, donelab, i0, i1, f0, in, out;
+
+  out = operands[0];
+  in = force_reg (DImode, operands[1]);
+  neglab = gen_label_rtx ();
+  donelab = gen_label_rtx ();
+  i0 = gen_reg_rtx (DImode);
+  i1 = gen_reg_rtx (DImode);
+  f0 = gen_reg_rtx (mode);
+
+  emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab);
+
+  emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_FLOAT (mode, in)));
+  emit_jump_insn (gen_jump (donelab));
+  emit_barrier ();
+
+  emit_label (neglab);
+
+  emit_insn (gen_lshrdi3 (i0, in, const1_rtx));
+  emit_insn (gen_anddi3 (i1, in, const1_rtx));
+  emit_insn (gen_iordi3 (i0, i0, i1));
+  emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_FLOAT (mode, i0)));
+  emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_PLUS (mode, f0, f0)));
+
+  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_floatunsdi (rtx *operands)
+sparc_emit_fixunsdi (rtx *operands, enum machine_mode mode)
 {
-  rtx neglab, donelab, i0, i1, f0, in, out;
-  enum machine_mode mode;
+  rtx neglab, donelab, i0, i1, f0, in, out, limit;
 
   out = operands[0];
-  in = force_reg (DImode, operands[1]);
-  mode = GET_MODE (out);
+  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_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab);
+  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_FLOAT (mode, in)));
+  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_lshrdi3 (i0, in, const1_rtx));
-  emit_insn (gen_anddi3 (i1, in, const1_rtx));
-  emit_insn (gen_iordi3 (i0, i0, i1));
-  emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_FLOAT (mode, i0)));
-  emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_PLUS (mode, f0, f0)));
+  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);
 }
@@ -6262,11 +6287,11 @@ sparc_emit_floatunsdi (rtx *operands)
 
    NOOP is nonzero if we have to follow this branch by a noop.  */
 
-char *
+const char *
 output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
                 int annul, int noop, rtx insn)
 {
-  static char string[50];
+  static char string[64];
   enum rtx_code code = GET_CODE (op);
   enum machine_mode mode = GET_MODE (XEXP (op, 0));
   rtx note;
@@ -6281,7 +6306,7 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
      to
      
      brz,pn %g1, .+12
-     nop
+      nop
      ba,pt %xcc, .LC30
      
      and
@@ -6291,7 +6316,7 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
      to
      
      brlz,pt %o1, .+16
-     nop
+      nop
      ba,pt %xcc, .LC29  */
 
   far = get_attr_length (insn) >= 3;
@@ -6372,10 +6397,10 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
            veryfar = 0;
        }
 
-      strcpy (p, ".+12\n\tnop\n\t");
+      strcpy (p, ".+12\n\t nop\n\t");
       if (annul || noop)
         p[3] = '6';
-      p += 11;
+      p += 12;
       if (veryfar)
        {
          strcpy (p, "b\t");
@@ -6393,7 +6418,7 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
   *p = '\0';
 
   if (noop)
-    strcpy (p, "\n\tnop");
+    strcpy (p, "\n\t nop");
 
   return string;
 }
@@ -6421,7 +6446,7 @@ epilogue_renumber (register rtx *where, int 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:
@@ -6721,7 +6746,8 @@ print_operand (FILE *file, rtx x, int code)
       /* Print out what we are using as the frame pointer.  This might
         be %fp, or might be %sp+offset.  */
       /* ??? What if offset is too big? Perhaps the caller knows it isn't? */
-      fprintf (file, "%s+"HOST_WIDE_INT_PRINT_DEC, frame_base_name, frame_base_offset);
+      fprintf (file, "%s+"HOST_WIDE_INT_PRINT_DEC,
+              reg_names[REGNO (frame_base_reg)], frame_base_offset);
       return;
     case '&':
       /* Print some local dynamic TLS name.  */
@@ -7083,7 +7109,7 @@ sparc_type_code (register tree 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
@@ -7093,16 +7119,16 @@ sparc_type_code (register tree 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
@@ -7125,6 +7151,7 @@ sparc_type_code (register tree type)
             existing front-ends.  */
          return (qualifiers | 7);      /* Who knows? */
 
+       case VECTOR_TYPE:
        case CHAR_TYPE:         /* GNU Pascal CHAR type.  Not used in C.  */
        case BOOLEAN_TYPE:      /* GNU Fortran BOOLEAN type.  */
        case FILE_TYPE:         /* GNU Pascal FILE type.  */
@@ -7208,7 +7235,7 @@ sparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
   /* Call __enable_execute_stack after writing onto the stack to make sure
      the stack address is accessible.  */
 #ifdef TRANSFER_FROM_TRAMPOLINE
-  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"),
+  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
                      LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
 #endif
 
@@ -7249,729 +7276,11 @@ sparc64_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
   /* Call __enable_execute_stack after writing onto the stack to make sure
      the stack address is accessible.  */
 #ifdef TRANSFER_FROM_TRAMPOLINE
-  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"),
+  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
                      LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
 #endif
 }
 \f
-/* Subroutines to support a flat (single) register window calling
-   convention.  */
-
-/* Single-register window sparc stack frames look like:
-
-             Before call                       After call
-        +-----------------------+      +-----------------------+
-   high |                      |       |                       |
-   mem  |  caller's temps.     |       |  caller's temps.      |
-       |                       |       |                       |
-        +-----------------------+      +-----------------------+
-       |                       |       |                       |
-        |  arguments on stack.  |      |  arguments on stack.  |
-       |                       |       |                       |
-        +-----------------------+FP+92->+-----------------------+
-       |  6 words to save      |       |  6 words to save      |
-       |  arguments passed     |       |  arguments passed     |
-       |  in registers, even   |       |  in registers, even   |
-               |  if not passed.       |       |  if not passed.       |
- SP+68->+-----------------------+FP+68->+-----------------------+
-        | 1 word struct addr   |       | 1 word struct addr    |
-        +-----------------------+FP+64->+-----------------------+
-        |                      |       |                       |
-        | 16 word reg save area        |       | 16 word reg save area |
-               |                       |       |                       |
-    SP->+-----------------------+   FP->+-----------------------+
-                                       | 4 word area for       |
-                                       | fp/alu reg moves      |
-                                FP-16->+-----------------------+
-                                       |                       |
-                                       |  local variables      |
-                                       |                       |
-                                       +-----------------------+
-                                       |                       |
-                                        |  fp register save     |
-                                       |                       |
-                                       +-----------------------+
-                                       |                       |
-                                        |  gp register save     |
-                                        |                      |
-                                       +-----------------------+
-                                       |                       |
-                                        |  alloca allocations   |
-                                       |                       |
-                                       +-----------------------+
-                                       |                       |
-                                        |  arguments on stack   |
-                                       |                       |
-                                SP+92->+-----------------------+
-                                        |  6 words to save      |
-                                       |  arguments passed     |
-                                        |  in registers, even   |
-   low                                         |  if not passed.       |
-   memory                       SP+68->+-----------------------+
-                                       | 1 word struct addr    |
-                                SP+64->+-----------------------+
-                                       |                       |
-                                       I 16 word reg save area |
-                                       |                       |
-                                   SP->+-----------------------+  */
-
-/* Structure to be filled in by sparc_flat_compute_frame_size with register
-   save masks, and offsets for the current function.  */
-
-struct sparc_frame_info
-{
-  HOST_WIDE_INT total_size;    /* # bytes that the entire frame takes up.  */
-  HOST_WIDE_INT var_size;      /* # bytes that variables take up.  */
-  int           args_size;     /* # bytes that outgoing arguments take up.  */
-  int           extra_size;    /* # bytes of extra gunk.  */
-  int           gp_reg_size;   /* # bytes needed to store gp regs.  */
-  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.  */
-  int           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;
-
-#define RETURN_ADDR_REGNUM 15
-#define HARD_FRAME_POINTER_MASK (1 << (HARD_FRAME_POINTER_REGNUM))
-#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
-\f
-/* Tell prologue and epilogue if register REGNO should be saved / restored.  */
-
-static bool
-sparc_flat_must_save_register_p (int regno)
-{
-  /* General case: call-saved registers live at some point.  */
-  if (!call_used_regs[regno] && regs_ever_live[regno])
-    return true;
-  
-  /* Frame pointer register (%i7) if needed.  */
-  if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
-    return true;
-
-  /* PIC register (%l7) if needed.  */
-  if (regno == (int) PIC_OFFSET_TABLE_REGNUM
-      && flag_pic && current_function_uses_pic_offset_table)
-    return true;
-
-  /* Return address register (%o7) if needed.  */
-  if (regno == RETURN_ADDR_REGNUM
-      && (regs_ever_live[RETURN_ADDR_REGNUM]
-         /* When the PIC offset table is used, the PIC register
-            is set by using a bare call that clobbers %o7.  */
-         || (flag_pic && current_function_uses_pic_offset_table)))
-    return true;
-
-  return false;
-}
-\f
-/* Return the bytes needed to compute the frame pointer from the current
-   stack pointer.  */
-
-HOST_WIDE_INT
-sparc_flat_compute_frame_size (HOST_WIDE_INT size)
-                               /* # of var. bytes allocated.  */
-{
-  int regno;
-  HOST_WIDE_INT total_size;    /* # bytes that the entire frame takes up.  */
-  HOST_WIDE_INT var_size;      /* # bytes that variables take up.  */
-  int           args_size;     /* # bytes that outgoing arguments take up.  */
-  int           extra_size;    /* # extra bytes.  */
-  int           gp_reg_size;   /* # bytes needed to store gp regs.  */
-  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.  */
-  int           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 (sparc_flat_must_save_register_p (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 && sparc_flat_must_save_register_p (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.  */
-
-static void
-sparc_flat_save_restore (FILE *file, const char *base_reg, int offset,
-                        unsigned long gmask, unsigned long fmask,
-                        const char *word_op, const char *doubleword_op,
-                        HOST_WIDE_INT 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 *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= "HOST_WIDE_INT_PRINT_DEC", "
-                "regs= %d/%d, args= %d, extra= %d\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)
-    {
-      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 * UNITS_PER_WORD)
-       {
-         if (size <= 4096)
-           {
-             fprintf (file, "\tadd\t%s, -"HOST_WIDE_INT_PRINT_DEC", %s\n",
-                      sp_str, 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, -"HOST_WIDE_INT_PRINT_DEC", %s"
-                                "\t%s# set up frame pointer\n",
-                          sp_str, size, fp_str, ASM_COMMENT_START);
-                 reg_offset += 4;
-               }
-           }
-         else
-           {
-             build_big_number (file, size, t1_str);
-             fprintf (file, "\tsub\t%s, %s, %s\n", 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.  */
-         HOST_WIDE_INT size1 = ((size - reg_offset + 64) + 15) & -16;
-
-         /* Amount to decrement %sp by, the second time.  */
-         HOST_WIDE_INT size2 = size - size1;
-
-         /* Offset to register save area from %sp after first decrement.  */
-         int offset = (int)(size1 - (size - reg_offset));
-         
-         if (size1 <= 4096)
-           {
-             fprintf (file, "\tadd\t%s, -"HOST_WIDE_INT_PRINT_DEC", %s\n",
-                      sp_str, size1, sp_str);
-             if (gmask & HARD_FRAME_POINTER_MASK)
-               {
-                 fprintf (file, "\tst\t%s, [%s+%d]\n"
-                                "\tsub\t%s, -"HOST_WIDE_INT_PRINT_DEC", %s"
-                                "\t%s# set up frame pointer\n",
-                          fp_str, sp_str, offset, sp_str, size1,
-                          fp_str, ASM_COMMENT_START);
-                 offset += 4;
-               }
-           }
-         else
-           {
-             build_big_number (file, size1, t1_str);
-             fprintf (file, "\tsub\t%s, %s, %s\n", 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, 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, 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);
-         if (size2 <= 4096)
-           fprintf (file, "\tadd\t%s, -"HOST_WIDE_INT_PRINT_DEC", %s\n",
-                    sp_str, size2, sp_str);
-         else
-           {
-             build_big_number (file, size2, t1_str);
-             fprintf (file, "\tsub\t%s, %s, %s\n", 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 *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)
-    {
-      int reg_offset = current_frame_info.reg_offset;
-      int reg_offset1;
-      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 > 4096)
-       build_big_number (file, size, t1_str);
-
-      if (frame_pointer_needed)
-       {
-         if (size > 4096)
-           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,"\tadd\t%s, -"HOST_WIDE_INT_PRINT_DEC", %s"
-                         "\t\t%s# sp not trusted here\n",
-                    fp_str, size, sp_str, ASM_COMMENT_START);
-       }
-
-      /* Is the entire register save area offsettable from %sp?  */
-      if (reg_offset < 4096 - 64 * UNITS_PER_WORD)
-       {
-         reg_offset1 = 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.  */
-         reg_offset1 = ((reg_offset - 64 - 16) + 15) & -16;
-
-         /* Offset to register save area from %sp.  */
-         reg_offset = reg_offset1 - reg_offset;
-
-         if (reg_offset1 > 4096)
-           {
-             build_big_number (file, reg_offset1, t1_str);
-             fprintf (file, "\tadd\t%s, %s, %s\n", sp_str, t1_str, sp_str);
-           }
-         else
-           fprintf (file, "\tsub\t%s, -%d, %s\n", sp_str, reg_offset1, 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, 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, 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 (reg_offset1 > 0)
-       {
-         size -= reg_offset1;
-         if (size > 4096)
-           build_big_number (file, size, t1_str);
-       }
-
-      if (current_function_returns_struct)
-       fprintf (file, "\tjmp\t%%o7+12\n");
-      else
-       fprintf (file, "\tretl\n");
-
-      /* If the only register saved is the return address, we need a
-        nop, unless we have an instruction to put into it.  Otherwise
-        we don't since reloading multiple registers doesn't reference
-        the register being loaded.  */
-
-      if (epilogue_delay)
-       {
-         if (size)
-           abort ();
-         final_scan_insn (XEXP (epilogue_delay, 0), file, 1, -2, 1, NULL);
-       }
-
-      else if (size > 4096)
-       fprintf (file, "\tadd\t%s, %s, %s\n", sp_str, t1_str, sp_str);
-
-      else if (size > 0)
-       fprintf (file, "\tsub\t%s, -"HOST_WIDE_INT_PRINT_DEC", %s\n",
-                sp_str, size, sp_str);
-
-      else
-       fprintf (file, "\tnop\n");
-    }
-
-  /* Reset state info for each function.  */
-  current_frame_info = zero_frame_info;
-
-  sparc_output_deferred_case_vectors ();
-}
-\f
-/* Define the number of delay slots needed for the function epilogue.
-
-   On the sparc, we need a slot if either no stack has been allocated,
-   or the only register saved is the return register.  */
-
-int
-sparc_flat_epilogue_delay_slots (void)
-{
-  if (!current_frame_info.initialized)
-    (void) sparc_flat_compute_frame_size (get_frame_size ());
-
-  if (current_frame_info.total_size == 0)
-    return 1;
-
-  return 0;
-}
-
-/* Return true if TRIAL is a valid insn for the epilogue delay slot.
-   Any single length instruction which doesn't reference the stack or frame
-   pointer is OK.  */
-
-int
-sparc_flat_eligible_for_epilogue_delay (rtx trial, int slot ATTRIBUTE_UNUSED)
-{
-  rtx pat = PATTERN (trial);
-
-  if (get_attr_length (trial) != 1)
-    return 0;
-
-  if (! reg_mentioned_p (stack_pointer_rtx, pat)
-      && ! reg_mentioned_p (frame_pointer_rtx, pat))
-    return 1;
-
-  return 0;
-}
-\f
 /* Adjust the cost of a scheduling dependency.  Return the new cost of
    a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
 
@@ -8139,18 +7448,6 @@ sparc_sched_init (FILE *dump ATTRIBUTE_UNUSED,
 }
   
 static int
-sparc_use_dfa_pipeline_interface (void)
-{
-  if ((1 << sparc_cpu) &
-      ((1 << PROCESSOR_ULTRASPARC) | (1 << PROCESSOR_CYPRESS) |
-       (1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) |
-       (1 << PROCESSOR_SPARCLITE86X) | (1 << PROCESSOR_TSC701) |
-       (1 << PROCESSOR_ULTRASPARC3)))
-    return 1;
-  return 0;
-}
-
-static int
 sparc_use_sched_lookahead (void)
 {
   if (sparc_cpu == PROCESSOR_ULTRASPARC
@@ -8410,8 +7707,8 @@ sparc_check_64 (rtx x, rtx insn)
 
 /* Returns assembly code to perform a DImode shift using
    a 64-bit global or out register on SPARC-V8+.  */
-char *
-sparc_v8plus_shift (rtx *operands, rtx insn, const char *opcode)
+const char *
+output_v8plus_shift (rtx *operands, rtx insn, const char *opcode)
 {
   static char asm_code[60];
 
@@ -8489,10 +7786,9 @@ sparc_elf_asm_named_section (const char *name, unsigned int flags)
 }
 #endif /* OBJECT_FORMAT_ELF */
 
-/* We do not allow sibling calls if -mflat, nor
-   we do not allow indirect calls to be optimized into sibling calls.
+/* We do not allow indirect calls to be optimized into sibling calls.
    
-   Also, on sparc 32-bit we cannot emit a sibling call when the
+   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
@@ -8508,9 +7804,7 @@ sparc_elf_asm_named_section (const char *name, unsigned int flags)
 static bool
 sparc_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
-  return (decl
-         && ! TARGET_FLAT
-         && (TARGET_ARCH64 || ! current_function_returns_struct));
+  return (decl && (TARGET_ARCH64 || ! current_function_returns_struct));
 }
 \f
 /* libfunc renaming.  */
@@ -8524,7 +7818,7 @@ sparc_init_libfuncs (void)
       /* 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. */
+        than .mul.  */
       set_optab_libfunc (smul_optab, SImode, "*.umul");
       set_optab_libfunc (sdiv_optab, SImode, "*.div");
       set_optab_libfunc (udiv_optab, SImode, "*.udiv");
@@ -8562,6 +7856,13 @@ sparc_init_libfuncs (void)
       set_conv_libfunc (ufix_optab,   SImode, TFmode, "_Q_qtou");
       set_conv_libfunc (sfloat_optab, TFmode, SImode, "_Q_itoq");
 
+      if (DITF_CONVERSION_LIBFUNCS)
+       {
+         set_conv_libfunc (sfix_optab,   DImode, TFmode, "_Q_qtoll");
+         set_conv_libfunc (ufix_optab,   DImode, TFmode, "_Q_qtoull");
+         set_conv_libfunc (sfloat_optab, TFmode, DImode, "_Q_lltoq");
+       }
+
       if (SUN_CONVERSION_LIBFUNCS)
        {
          set_conv_libfunc (sfix_optab, DImode, SFmode, "__ftoll");
@@ -8603,31 +7904,6 @@ sparc_init_libfuncs (void)
   gofast_maybe_init_libfuncs ();
 }
 \f
-/* ??? Similar to the standard section selection, but force reloc-y-ness
-   if SUNOS4_SHARED_LIBRARIES.  Unclear why this helps (as opposed to
-   pretending PIC always on), but that's what the old code did.  */
-
-static void
-sparc_aout_select_section (tree t, int reloc, unsigned HOST_WIDE_INT align)
-{
-  default_select_section (t, reloc | SUNOS4_SHARED_LIBRARIES, align);
-}
-
-/* Use text section for a constant unless we need more alignment than
-   that offers.  */
-
-static void
-sparc_aout_select_rtx_section (enum machine_mode mode, rtx x,
-                              unsigned HOST_WIDE_INT align)
-{
-  if (align <= MAX_TEXT_ALIGN
-      && ! (flag_pic && (symbolic_operand (x, mode)
-                        || SUNOS4_SHARED_LIBRARIES)))
-    readonly_data_section ();
-  else
-    data_section ();
-}
-
 int
 sparc_extra_constraint_check (rtx op, int c, int strict)
 {
@@ -8935,7 +8211,7 @@ sparc_rtx_costs (rtx x, int code, int outer_code, int *total)
       return true;
 
     case IF_THEN_ELSE:
-      /* Conditional moves. */
+      /* Conditional moves.  */
       switch (sparc_cpu)
        {
        case PROCESSOR_ULTRASPARC:
@@ -9071,6 +8347,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   epilogue_completed = 1;
   no_new_pseudos = 1;
   current_function_uses_only_leaf_regs = 1;
+  reset_block_changes ();
 
   emit_note (NOTE_INSN_PROLOGUE_END);