OSDN Git Service

* config/alpha/alpha.md, config/arm/arm.c, config/arm/arm.h,
[pf3gnuchains/gcc-fork.git] / gcc / config / sparc / sparc.c
index 891da83..1cb61c7 100644 (file)
@@ -1,5 +1,6 @@
 /* Subroutines for insn-output.c for Sun SPARC.
-   Copyright (C) 1987, 88, 89, 92-98, 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
    64 bit SPARC V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
    at Cygnus Support.
@@ -30,16 +31,20 @@ Boston, MA 02111-1307, USA.  */
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "insn-flags.h"
 #include "output.h"
 #include "insn-attr.h"
 #include "flags.h"
 #include "function.h"
 #include "expr.h"
+#include "optabs.h"
+#include "libfuncs.h"
 #include "recog.h"
 #include "toplev.h"
 #include "ggc.h"
 #include "tm_p.h"
+#include "debug.h"
+#include "target.h"
+#include "target-def.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.
@@ -82,7 +87,7 @@ static rtx leaf_label;
    registers.  FRAME_POINTER_REGNUM cannot be remapped by
    this function to eliminate it.  You must use -fomit-frame-pointer
    to get that.  */
-char leaf_reg_remap[] =
+const char leaf_reg_remap[] =
 { 0, 1, 2, 3, 4, 5, 6, 7,
   -1, -1, -1, -1, -1, -1, 14, -1,
   -1, -1, -1, -1, -1, -1, -1, -1,
@@ -98,6 +103,24 @@ char leaf_reg_remap[] =
   88, 89, 90, 91, 92, 93, 94, 95,
   96, 97, 98, 99, 100};
 
+/* Vector, indexed by hard register number, which contains 1
+   for a register that is allowable in a candidate for leaf
+   function treatment.  */
+char sparc_leaf_regs[] =
+{ 1, 1, 1, 1, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 1, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 0, 1,
+  1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1};
+
 #endif
 
 /* Name of where we pretend to think the frame pointer points.
@@ -108,7 +131,6 @@ char leaf_reg_remap[] =
 static const char *frame_base_name;
 static int frame_base_offset;
 
-static rtx pic_setup_code      PARAMS ((void));
 static void sparc_init_modes   PARAMS ((void));
 static int save_regs           PARAMS ((FILE *, int, int, const char *,
                                       int, int, int));
@@ -135,7 +157,27 @@ static rtx *ultra_find_type PARAMS ((int, rtx *, int));
 static void ultra_build_types_avail PARAMS ((rtx *, int));
 static void ultra_flush_pipeline PARAMS ((void));
 static void ultra_rescan_pipeline_state PARAMS ((rtx *, int));
-static int set_extends PARAMS ((rtx, rtx));
+static int set_extends PARAMS ((rtx));
+static void output_restore_regs PARAMS ((FILE *, int));
+static void sparc_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
+static void sparc_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
+static void sparc_flat_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
+static void sparc_flat_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
+static void sparc_nonflat_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT,
+                                                    int));
+static void sparc_nonflat_function_prologue PARAMS ((FILE *, HOST_WIDE_INT,
+                                                    int));
+static void sparc_elf_asm_named_section PARAMS ((const char *, unsigned int));
+
+static void ultrasparc_sched_reorder PARAMS ((FILE *, int, rtx *, int));
+static int ultrasparc_variable_issue PARAMS ((rtx));
+static void ultrasparc_sched_init PARAMS ((void));
+
+static int sparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
+static int sparc_issue_rate PARAMS ((void));
+static int sparc_variable_issue PARAMS ((FILE *, int, rtx, int));
+static void sparc_sched_init PARAMS ((FILE *, int, int));
+static int sparc_sched_reorder PARAMS ((FILE *, int, rtx *, int *, int));
 \f
 /* Option handling.  */
 
@@ -157,7 +199,26 @@ struct sparc_cpu_select sparc_select[] =
 
 /* CPU type.  This is set from TARGET_CPU_DEFAULT and -m{cpu,tune}=xxx.  */
 enum processor_type sparc_cpu;
-
+\f
+/* Initialize the GCC target structure.  */
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE sparc_output_function_prologue
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE sparc_output_function_epilogue
+
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST sparc_adjust_cost
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE sparc_issue_rate
+#undef TARGET_SCHED_VARIABLE_ISSUE
+#define TARGET_SCHED_VARIABLE_ISSUE sparc_variable_issue
+#undef TARGET_SCHED_INIT
+#define TARGET_SCHED_INIT sparc_sched_init
+#undef TARGET_SCHED_REORDER
+#define TARGET_SCHED_REORDER sparc_sched_reorder
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
 /* Validate and override various options, and do some machine dependent
    initialization.  */
 
@@ -165,9 +226,9 @@ void
 sparc_override_options ()
 {
   static struct code_model {
-    const char *name;
-    int value;
-  } cmodels[] = {
+    const char *const name;
+    const int value;
+  } const cmodels[] = {
     { "32", CM_32 },
     { "medlow", CM_MEDLOW },
     { "medmid", CM_MEDMID },
@@ -175,12 +236,12 @@ sparc_override_options ()
     { "embmedany", CM_EMBMEDANY },
     { 0, 0 }
   };
-  struct code_model *cmodel;
+  const struct code_model *cmodel;
   /* Map TARGET_CPU_DEFAULT to value for -m{arch,tune}=.  */
   static struct cpu_default {
-    int cpu;
-    const char *name;
-  } cpu_default[] = {
+    const int cpu;
+    const char *const name;
+  } const cpu_default[] = {
     /* There must be one entry here for each TARGET_CPU value.  */
     { TARGET_CPU_sparc, "cypress" },
     { TARGET_CPU_sparclet, "tsc701" },
@@ -193,14 +254,14 @@ sparc_override_options ()
     { TARGET_CPU_ultrasparc, "ultrasparc" },
     { 0, 0 }
   };
-  struct cpu_default *def;
+  const struct cpu_default *def;
   /* Table of values for -m{cpu,tune}=.  */
   static struct cpu_table {
-    const char *name;
-    enum processor_type processor;
-    int disable;
-    int enable;
-  } cpu_table[] = {
+    const char *const name;
+    const enum processor_type processor;
+    const int disable;
+    const int enable;
+  } const cpu_table[] = {
     { "v7",         PROCESSOR_V7, MASK_ISA, 0 },
     { "cypress",    PROCESSOR_CYPRESS, MASK_ISA, 0 },
     { "v8",         PROCESSOR_V8, MASK_ISA, MASK_V8 },
@@ -222,31 +283,25 @@ sparc_override_options ()
     { "ultrasparc", PROCESSOR_ULTRASPARC, MASK_ISA, MASK_V9
     /* Although insns using %y are deprecated, it is a clear win on current
        ultrasparcs. */
-                                                   |MASK_DEPRECATED_V8_INSNS },
+                                                   |MASK_DEPRECATED_V8_INSNS},
     { 0, 0, 0, 0 }
   };
-  struct cpu_table *cpu;
-  struct sparc_cpu_select *sel;
+  const struct cpu_table *cpu;
+  const struct sparc_cpu_select *sel;
   int fpu;
   
 #ifndef SPARC_BI_ARCH
   /* Check for unsupported architecture size.  */
   if (! TARGET_64BIT != DEFAULT_ARCH32_P)
-    {
-      error ("%s is not supported by this configuration",
-            DEFAULT_ARCH32_P ? "-m64" : "-m32");
-    }
+    error ("%s is not supported by this configuration",
+          DEFAULT_ARCH32_P ? "-m64" : "-m32");
 #endif
 
-  /* At the moment we don't allow different pointer size and architecture */
-  if (! TARGET_64BIT != ! TARGET_PTR64)
+  /* We force all 64bit archs to use 128 bit long double */
+  if (TARGET_64BIT && ! TARGET_LONG_DOUBLE_128)
     {
-      error ("-mptr%d not allowed on -m%d",
-            TARGET_PTR64 ? 64 : 32, TARGET_64BIT ? 64 : 32);
-      if (TARGET_64BIT)
-       target_flags |= MASK_PTR64;
-      else
-        target_flags &= ~MASK_PTR64;
+      error ("-mlong-double-64 not allowed with -m64");
+      target_flags |= MASK_LONG_DOUBLE_128;
     }
 
   /* Code model selection.  */
@@ -315,6 +370,16 @@ sparc_override_options ()
       target_flags &= ~MASK_FPU_SET;
     }
 
+  /* Don't allow -mvis if FPU is disabled.  */
+  if (! TARGET_FPU)
+    target_flags &= ~MASK_VIS;
+
+  /* -mvis assumes UltraSPARC+, so we are sure v9 instructions
+     are available.
+     -m64 also implies v9.  */
+  if (TARGET_VIS || TARGET_ARCH64)
+    target_flags |= MASK_V9;
+
   /* Use the deprecated v8 insns for sparc64 in 32 bit mode.  */
   if (TARGET_V9 && TARGET_ARCH32)
     target_flags |= MASK_DEPRECATED_V8_INSNS;
@@ -327,10 +392,6 @@ sparc_override_options ()
   if (TARGET_ARCH32)
     target_flags &= ~MASK_STACK_BIAS;
     
-  /* Don't allow -mvis if FPU is disabled.  */
-  if (! TARGET_FPU)
-    target_flags &= ~MASK_VIS;
-
   /* Supply a default value for align_functions.  */
   if (align_functions == 0 && sparc_cpu == PROCESSOR_ULTRASPARC)
     align_functions = 32;
@@ -369,8 +430,7 @@ v9_regcmp_p (code)
 /* Operand constraints.  */
 
 /* Return non-zero only if OP is a register of mode MODE,
-   or const0_rtx.  Don't allow const0_rtx if TARGET_LIVE_G0 because
-   %g0 may contain anything.  */
+   or const0_rtx.  */
 
 int
 reg_or_0_operand (op, mode)
@@ -379,8 +439,6 @@ reg_or_0_operand (op, mode)
 {
   if (register_operand (op, mode))
     return 1;
-  if (TARGET_LIVE_G0)
-    return 0;
   if (op == const0_rtx)
     return 1;
   if (GET_MODE (op) == VOIDmode && GET_CODE (op) == CONST_DOUBLE
@@ -1098,7 +1156,7 @@ uns_small_int (op, mode)
   return (GET_CODE (op) == CONST_INT
          && ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000)
              || (INTVAL (op) >= 0xFFFFF000
-                  && INTVAL (op) < 0x100000000)));
+                  && INTVAL (op) <= 0xFFFFFFFF)));
 #else
   return ((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000)
          || (GET_CODE (op) == CONST_DOUBLE
@@ -1124,16 +1182,6 @@ clobbered_register (op, mode)
   return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);
 }
 
-/* Return 1 if OP is const0_rtx, used for TARGET_LIVE_G0 insns.  */
-
-int
-zero_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return op == const0_rtx;
-}
-
 /* Return 1 if OP is a valid operand for the source of a move insn.  */
 
 int
@@ -1174,7 +1222,8 @@ input_operand (op, mode)
                  (SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))
                   && (((CONST_DOUBLE_LOW (op) & 0x80000000) == 0
                        && CONST_DOUBLE_HIGH (op) == 0)
-                      || (CONST_DOUBLE_HIGH (op) == -1)))
+                      || (CONST_DOUBLE_HIGH (op) == -1
+                          && CONST_DOUBLE_LOW (op) & 0x80000000) != 0))
 #endif
                  ))))
     return 1;
@@ -1812,12 +1861,17 @@ sparc_emit_set_const64 (op0, op1)
   rtx temp;
 
   /* Sanity check that we know what we are working with.  */
-  if (! TARGET_ARCH64
-      || GET_CODE (op0) != REG
-      || (REGNO (op0) >= SPARC_FIRST_FP_REG
-         && REGNO (op0) <= SPARC_LAST_V9_FP_REG))
+  if (! TARGET_ARCH64)
     abort ();
 
+  if (GET_CODE (op0) != SUBREG)
+    {
+      if (GET_CODE (op0) != REG
+         || (REGNO (op0) >= SPARC_FIRST_FP_REG
+             && REGNO (op0) <= SPARC_LAST_V9_FP_REG))
+       abort ();
+    }
+
   if (reload_in_progress || reload_completed)
     temp = op0;
   else
@@ -2361,17 +2415,16 @@ eligible_for_epilogue_delay (trial, slot)
   if (get_attr_length (trial) != 1)
     return 0;
 
-  /* If %g0 is live, there are lots of things we can't handle.
-     Rather than trying to find them all now, let's punt and only
-     optimize things as necessary.  */
-  if (TARGET_LIVE_G0)
-    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 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.  */
@@ -2383,27 +2436,33 @@ eligible_for_epilogue_delay (trial, slot)
       return 0;
     }
 
-  /* If only trivial `restore' insns work, nothing can go in the
-     delay slot.  */
-  else if (TARGET_BROKEN_SAVERESTORE)
-    return 0;
-
   pat = PATTERN (trial);
 
   /* Otherwise, only operations which can be done in tandem with
      a `restore' or `return' insn can go into the delay slot.  */
   if (GET_CODE (SET_DEST (pat)) != REG
-      || REGNO (SET_DEST (pat)) >= 32
       || REGNO (SET_DEST (pat)) < 24)
     return 0;
 
+  /* If this instruction sets up floating point register and we have a return
+     instruction, it can probably go in.  But restore will not work
+     with FP_REGS.  */
+  if (REGNO (SET_DEST (pat)) >= 32)
+    {
+      if (TARGET_V9 && ! epilogue_renumber (&pat, 1)
+         && (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE))
+       return 1;
+      return 0;
+    }
+
   /* The set of insns matched here must agree precisely with the set of
      patterns paired with a RETURN in sparc.md.  */
 
   src = SET_SRC (pat);
 
   /* This matches "*return_[qhs]i" or even "*return_di" on TARGET_ARCH64.  */
-  if (arith_operand (src, GET_MODE (src)))
+  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);
@@ -2412,7 +2471,8 @@ eligible_for_epilogue_delay (trial, slot)
     }
 
   /* This matches "*return_di".  */
-  else if (arith_double_operand (src, GET_MODE (src)))
+  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".  */
@@ -2464,6 +2524,100 @@ eligible_for_epilogue_delay (trial, slot)
   return 0;
 }
 
+/* Return nonzero if TRIAL can go into the sibling call
+   delay slot.  */
+
+int
+eligible_for_sibcall_delay (trial)
+     rtx trial;
+{
+  rtx pat, src;
+
+  if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
+    return 0;
+
+  if (get_attr_length (trial) != 1 || profile_block_flag == 2)
+    return 0;
+
+  pat = PATTERN (trial);
+
+  if (current_function_uses_only_leaf_regs)
+    {
+      /* 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)
+       return 0;
+
+      /* %g1 is used to build the function address */
+      if (reg_mentioned_p (gen_rtx_REG (Pmode, 1), pat))
+       return 0;
+
+      return 1;
+    }
+
+  /* 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)) >= 32)
+    return 0;
+
+  /* If it mentions %o7, it can't go in, because sibcall will clobber it
+     in most cases.  */
+  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 (x)
      rtx x;
@@ -2514,10 +2668,12 @@ int
 short_branch (uid1, uid2)
      int uid1, uid2;
 {
-  unsigned int delta = insn_addresses[uid1] - insn_addresses[uid2];
-  if (delta + 1024 < 2048)
+  int delta = INSN_ADDRESSES (uid1) - INSN_ADDRESSES (uid2);
+
+  /* Leave a few words of "slop".  */
+  if (delta >= -1023 && delta <= 1022)
     return 1;
-  /* warning ("long branch, distance %d", delta); */
+
   return 0;
 }
 
@@ -2655,8 +2811,8 @@ legitimize_pic_address (orig, mode, reg)
        address = orig;
 
       pic_ref = gen_rtx_MEM (Pmode,
-                        gen_rtx_PLUS (Pmode,
-                                 pic_offset_table_rtx, address));
+                            gen_rtx_PLUS (Pmode,
+                                          pic_offset_table_rtx, address));
       current_function_uses_pic_offset_table = 1;
       RTX_UNCHANGING_P (pic_ref) = 1;
       insn = emit_move_insn (reg, pic_ref);
@@ -2694,7 +2850,7 @@ legitimize_pic_address (orig, mode, reg)
       if (GET_CODE (offset) == CONST_INT)
        {
          if (SMALL_INT (offset))
-           return plus_constant_for_output (base, INTVAL (offset));
+           return plus_constant (base, INTVAL (offset));
          else if (! reload_in_progress && ! reload_completed)
            offset = force_reg (Pmode, offset);
          else
@@ -2712,33 +2868,13 @@ legitimize_pic_address (orig, mode, reg)
   return orig;
 }
 
-/* Return the RTX for insns to set the PIC register.  */
-
-static rtx
-pic_setup_code ()
-{
-  rtx seq;
-
-  start_sequence ();
-  emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
-                        get_pc_symbol));
-  seq = gen_sequence ();
-  end_sequence ();
-
-  return seq;
-}
-
-/* Emit special PIC prologues and epilogues.  */
+/* Emit special PIC prologues.  */
 
 void
-finalize_pic ()
+load_pic_register ()
 {
   /* Labels to get the PC in the prologue of this function.  */
   int orig_flag_pic = flag_pic;
-  rtx insn;
-
-  if (current_function_uses_pic_offset_table == 0)
-    return;
 
   if (! flag_pic)
     abort ();
@@ -2755,7 +2891,7 @@ finalize_pic ()
       if (align > 0)
        ASM_OUTPUT_ALIGN (asm_out_file, align);
       ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LGETPC", 0);
-      fputs ("\tretl\n\tadd %o7,%l7,%l7\n", asm_out_file);
+      fputs ("\tretl\n\tadd\t%o7, %l7, %l7\n", asm_out_file);
     }
 
   /* Initialize every time through, since we can't easily
@@ -2764,16 +2900,8 @@ finalize_pic ()
   get_pc_symbol = gen_rtx_SYMBOL_REF (Pmode, get_pc_symbol_name);
   flag_pic = 0;
 
-  emit_insn_after (pic_setup_code (), get_insns ());
-
-  /* Insert the code in each nonlocal goto receiver.
-     If you make changes here or to the nonlocal_goto_receiver
-     pattern, make sure the unspec_volatile numbers still
-     match.  */
-  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
-       && XINT (PATTERN (insn), 1) == 5)
-      emit_insn_after (pic_setup_code (), insn);
+  emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
+                        get_pc_symbol));
 
   flag_pic = orig_flag_pic;
 
@@ -2831,10 +2959,13 @@ mem_min_alignment (mem, desired)
        {
          /* Check if the compiler has recorded some information
             about the alignment of the base REG.  If reload has
-            completed, we already matched with proper alignments.  */
-         if (((cfun != 0 && REGNO_POINTER_ALIGN (regno) >= desired)
-              || reload_completed)
-             && ((INTVAL (offset) & (desired - 1)) == 0))
+            completed, we already matched with proper alignments.
+            If not running global_alloc, reload might give us
+            unaligned pointer to local stack though.  */
+         if (((cfun != 0
+               && REGNO_POINTER_ALIGN (regno) >= desired * BITS_PER_UNIT)
+              || (optimize && reload_completed))
+             && (INTVAL (offset) & (desired - 1)) == 0)
            return 1;
        }
       else
@@ -3161,11 +3292,11 @@ restore_regs (file, low, high, base, offset, n_regs)
                       base, offset + 4 * n_regs, reg_names[i]),
              n_regs += 2;
            else
-             fprintf (file, "\tld\t[%s+%d],%s\n",
+             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",
+           fprintf (file, "\tld\t[%s+%d], %s\n",
                     base, offset + 4 * n_regs + 4, reg_names[i+1]),
            n_regs += 2;
        }
@@ -3271,7 +3402,7 @@ build_big_number (file, num, reg)
 /* Output any necessary .register pseudo-ops.  */
 void
 sparc_output_scratch_registers (file)
-     FILE *file;
+     FILE *file ATTRIBUTE_UNUSED;
 {
 #ifdef HAVE_AS_REGISTER_PSEUDO_OP
   int i;
@@ -3294,12 +3425,40 @@ sparc_output_scratch_registers (file)
 #endif
 }
 
+/* This function generates the assembly code for function entry.
+   FILE is a stdio stream to output the code to.
+   SIZE is an int: how many units of temporary storage to allocate.
+   Refer to the array `regs_ever_live' to determine which registers
+   to save; `regs_ever_live[I]' is nonzero if register number I
+   is ever used in the function.  This macro is responsible for
+   knowing which registers should not be saved even if used.  */
+
+/* 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.
+
+   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.  */
+
+static void
+sparc_output_function_prologue (file, size)
+     FILE *file;
+     HOST_WIDE_INT size;
+{
+  if (TARGET_FLAT)
+    sparc_flat_function_prologue (file, size);
+  else
+    sparc_nonflat_function_prologue (file, size,
+                                    current_function_uses_only_leaf_regs);
+}
+
 /* Output code for the function prologue.  */
 
-void
-output_function_prologue (file, size, leaf_function)
+static void
+sparc_nonflat_function_prologue (file, size, leaf_function)
      FILE *file;
-     int size;
+     HOST_WIDE_INT size;
      int leaf_function;
 {
   sparc_output_scratch_registers (file);
@@ -3324,7 +3483,7 @@ output_function_prologue (file, size, leaf_function)
 
   if (actual_fsize == 0)
     /* do nothing.  */ ;
-  else if (! leaf_function && ! TARGET_BROKEN_SAVERESTORE)
+  else if (! leaf_function)
     {
       if (actual_fsize <= 4096)
        fprintf (file, "\tsave\t%%sp, -%d, %%sp\n", actual_fsize);
@@ -3339,26 +3498,6 @@ output_function_prologue (file, size, leaf_function)
          fprintf (file, "\tsave\t%%sp, %%g1, %%sp\n");
        }
     }
-  else if (! leaf_function && TARGET_BROKEN_SAVERESTORE)
-    {
-      /* We assume the environment will properly handle or otherwise avoid
-        trouble associated with an interrupt occurring after the `save' or
-        trap occurring during it.  */
-      fprintf (file, "\tsave\n");
-
-      if (actual_fsize <= 4096)
-       fprintf (file, "\tadd\t%%fp, -%d, %%sp\n", actual_fsize);
-      else if (actual_fsize <= 8192)
-       {
-         fprintf (file, "\tadd\t%%fp, -4096, %%sp\n");
-         fprintf (file, "\tadd\t%%fp, -%d, %%sp\n", actual_fsize - 4096);
-       }
-      else
-       {
-         build_big_number (file, -actual_fsize, "%g1");
-         fprintf (file, "\tadd\t%%fp, %%g1, %%sp\n");
-       }
-    }
   else /* leaf function */
     {
       if (actual_fsize <= 4096)
@@ -3447,12 +3586,66 @@ output_function_prologue (file, size, leaf_function)
     }
 }
 
+/* Output code to restore any call saved registers.  */
+
+static void
+output_restore_regs (file, leaf_function)
+     FILE *file;
+     int leaf_function;
+{
+  int offset, n_regs;
+  const char *base;
+
+  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;
+    }
+
+  n_regs = 0;
+  if (TARGET_EPILOGUE && ! leaf_function)
+    /* ??? Originally saved regs 0-15 here.  */
+    n_regs = restore_regs (file, 0, 8, base, offset, 0);
+  else if (leaf_function)
+    /* ??? Originally saved regs 0-31 here.  */
+    n_regs = restore_regs (file, 0, 8, base, offset, 0);
+  if (TARGET_EPILOGUE)
+    restore_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs);
+}
+
+/* This function generates the assembly code for function exit,
+   on machines that need it.
+
+   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.  */
+
+static void
+sparc_output_function_epilogue (file, size)
+     FILE *file;
+     HOST_WIDE_INT size;
+{
+  if (TARGET_FLAT)
+    sparc_flat_function_epilogue (file, size);
+  else
+    sparc_nonflat_function_epilogue (file, size,
+                                    current_function_uses_only_leaf_regs);
+}
+
 /* Output code for the function epilogue.  */
 
-void
-output_function_epilogue (file, size, leaf_function)
+static void
+sparc_nonflat_function_epilogue (file, size, leaf_function)
      FILE *file;
-     int size ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
      int leaf_function;
 {
   const char *ret;
@@ -3481,35 +3674,8 @@ output_function_epilogue (file, size, leaf_function)
       goto output_vectors;                                                    
     }
 
-  /* Restore any call saved registers.  */
   if (num_gfregs)
-    {
-      int offset, n_regs;
-      const char *base;
-
-      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;
-       }
-
-      n_regs = 0;
-      if (TARGET_EPILOGUE && ! leaf_function)
-       /* ??? Originally saved regs 0-15 here.  */
-       n_regs = restore_regs (file, 0, 8, base, offset, 0);
-      else if (leaf_function)
-       /* ??? Originally saved regs 0-31 here.  */
-       n_regs = restore_regs (file, 0, 8, base, offset, 0);
-      if (TARGET_EPILOGUE)
-       restore_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs);
-    }
+    output_restore_regs (file, leaf_function);
 
   /* Work out how to skip the caller's unimp instruction if required.  */
   if (leaf_function)
@@ -3524,8 +3690,17 @@ output_function_epilogue (file, size, leaf_function)
 
       if (! leaf_function)
        {
+         if (current_function_calls_eh_return)
+           {
+             if (current_function_epilogue_delay_list)
+               abort ();
+             if (SKIP_CALLERS_UNIMP_P)
+               abort ();
+
+             fputs ("\trestore\n\tretl\n\tadd\t%sp, %g1, %sp\n", file);
+           }
          /* If we wound up with things in our delay slot, flush them here.  */
-         if (current_function_epilogue_delay_list)
+         else if (current_function_epilogue_delay_list)
            {
              rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0));
 
@@ -3565,6 +3740,8 @@ output_function_epilogue (file, size, leaf_function)
          else
            fprintf (file, "\t%s\n\trestore\n", ret);
        }
+      else if (current_function_calls_eh_return)
+       abort ();
       /* All of the following cases are for leaf functions.  */
       else if (current_function_epilogue_delay_list)
        {
@@ -3599,6 +3776,149 @@ output_function_epilogue (file, size, leaf_function)
  output_vectors:
   sparc_output_deferred_case_vectors ();
 }
+
+/* Output a sibling call.  */
+
+const char *
+output_sibcall (insn, call_operand)
+     rtx insn, 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);
+         PATTERN (delay) = gen_blockage ();
+         INSN_CODE (delay) = -1;
+         delay_slot = 0;
+       }
+      output_restore_regs (asm_out_file, leaf_regs);
+    }
+
+  operands[0] = call_operand;
+
+  if (leaf_regs)
+    {
+#ifdef HAVE_AS_RELAX_OPTION
+      /* If as and ld are relaxing tail call insns into branch always,
+        use or %o7,%g0,X; call Y; or X,%g0,%o7 always, so that it can
+        be optimized.  With sethi/jmpl as nor ld has no easy way how to
+        find out if somebody does not branch between the sethi and jmpl.  */
+      int spare_slot = 0;
+#else
+      int spare_slot = ((TARGET_ARCH32 || TARGET_CM_MEDLOW) && ! flag_pic);
+#endif
+      int size = 0;
+
+      if ((actual_fsize || ! spare_slot) && delay_slot)
+       {
+         rtx delay = NEXT_INSN (insn);
+
+         if (! delay)
+           abort ();
+
+         final_scan_insn (delay, asm_out_file, 1, 0, 1);
+         PATTERN (delay) = gen_blockage ();
+         INSN_CODE (delay) = -1;
+         delay_slot = 0;
+       }
+      if (actual_fsize)
+       {
+         if (actual_fsize <= 4096)
+           size = actual_fsize;
+         else if (actual_fsize <= 8192)
+           {
+             fputs ("\tsub\t%sp, -4096, %sp\n", asm_out_file);
+             size = actual_fsize - 4096;
+           }
+         else if ((actual_fsize & 0x3ff) == 0)
+           fprintf (asm_out_file,
+                    "\tsethi\t%%hi(%d), %%g1\n\tadd\t%%sp, %%g1, %%sp\n",
+                    actual_fsize);
+         else
+           {
+             fprintf (asm_out_file,
+                      "\tsethi\t%%hi(%d), %%g1\n\tor\t%%g1, %%lo(%d), %%g1\n",
+                      actual_fsize, actual_fsize);
+             fputs ("\tadd\t%%sp, %%g1, %%sp\n", asm_out_file);
+           }
+       }
+      if (spare_slot)
+       {
+         output_asm_insn ("sethi\t%%hi(%a0), %%g1", operands);
+         output_asm_insn ("jmpl\t%%g1 + %%lo(%a0), %%g0", operands);
+         if (size)
+           fprintf (asm_out_file, "\t sub\t%%sp, -%d, %%sp\n", size);
+         else if (! delay_slot)
+           fputs ("\t nop\n", asm_out_file);
+       }
+      else
+       {
+         if (size)
+           fprintf (asm_out_file, "\tsub\t%%sp, -%d, %%sp\n", size);
+         /* Use or with rs2 %%g0 instead of mov, so that as/ld can optimize
+            it into branch if possible.  */
+         output_asm_insn ("or\t%%o7, %%g0, %%g1", operands);
+         output_asm_insn ("call\t%a0, 0", operands);
+         output_asm_insn (" or\t%%g1, %%g0, %%o7", operands);
+       }
+      return "";
+    }
+
+  output_asm_insn ("call\t%a0, 0", operands);
+  if (delay_slot)
+    {
+      rtx delay = NEXT_INSN (insn), pat;
+
+      if (! delay)
+       abort ();
+
+      pat = PATTERN (delay);
+      if (GET_CODE (pat) != SET)
+       abort ();
+
+      operands[0] = SET_DEST (pat);
+      pat = SET_SRC (pat);
+      switch (GET_CODE (pat))
+       {
+       case PLUS:
+         operands[1] = XEXP (pat, 0);
+         operands[2] = XEXP (pat, 1);
+         output_asm_insn (" restore %r1, %2, %Y0", operands);
+         break;
+       case LO_SUM:
+         operands[1] = XEXP (pat, 0);
+         operands[2] = XEXP (pat, 1);
+         output_asm_insn (" restore %r1, %%lo(%a2), %Y0", operands);
+         break;
+       case ASHIFT:
+         operands[1] = XEXP (pat, 0);
+         output_asm_insn (" restore %r1, %r1, %Y0", operands);
+         break;
+       default:
+         operands[1] = pat;
+         output_asm_insn (" restore %%g0, %1, %Y0", operands);
+         break;
+       }
+      PATTERN (delay) = gen_blockage ();
+      INSN_CODE (delay) = -1;
+    }
+  else
+    fputs ("\t restore\n", asm_out_file);
+  return "";
+}
 \f
 /* Functions for handling argument passing.
 
@@ -3725,6 +4045,7 @@ function_arg_slotno (cum, mode, type, named, incoming_p, pregno, ppadding)
     case HImode : case CHImode :
     case SImode : case CSImode :
     case DImode : case CDImode :
+    case TImode : case CTImode :
       if (slotno >= SPARC_INT_ARG_MAX)
        return -1;
       regno = regbase + slotno;
@@ -3831,22 +4152,28 @@ struct function_arg_record_value_parms
 {
   rtx ret;
   int slotno, named, regbase;
-  int nregs, intoffset;
+  unsigned int nregs;
+  int intoffset;
 };
 
 static void function_arg_record_value_3
-       PARAMS ((int, struct function_arg_record_value_parms *));
+       PARAMS ((HOST_WIDE_INT, struct function_arg_record_value_parms *));
 static void function_arg_record_value_2
-       PARAMS ((tree, int, struct function_arg_record_value_parms *));
+       PARAMS ((tree, HOST_WIDE_INT,
+                struct function_arg_record_value_parms *));
 static void function_arg_record_value_1
-        PARAMS ((tree, int, struct function_arg_record_value_parms *));
+        PARAMS ((tree, HOST_WIDE_INT,
+                struct function_arg_record_value_parms *));
 static rtx function_arg_record_value
        PARAMS ((tree, enum machine_mode, int, int, int));
 
+/* A subroutine of function_arg_record_value.  Traverse the structure
+   recusively and determine how many registers will be required.  */
+
 static void
 function_arg_record_value_1 (type, startbitpos, parms)
      tree type;
-     int startbitpos;
+     HOST_WIDE_INT startbitpos;
      struct function_arg_record_value_parms *parms;
 {
   tree field;
@@ -3874,15 +4201,16 @@ function_arg_record_value_1 (type, startbitpos, parms)
     {
       if (TREE_CODE (field) == FIELD_DECL)
        {
-         int bitpos = startbitpos;
-         if (DECL_FIELD_BITPOS (field))
-           bitpos += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
+         HOST_WIDE_INT bitpos = startbitpos;
+
+         if (DECL_SIZE (field) != 0
+             && host_integerp (bit_position (field), 1))
+           bitpos += int_bit_position (field);
+
          /* ??? FIXME: else assume zero offset.  */
 
          if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
-           {
-             function_arg_record_value_1 (TREE_TYPE (field), bitpos, parms);
-           }
+           function_arg_record_value_1 (TREE_TYPE (field), bitpos, parms);
          else if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
                   && TARGET_FPU
                   && ! packed_p
@@ -3916,23 +4244,29 @@ function_arg_record_value_1 (type, startbitpos, parms)
     }
 }
 
-/* Handle recursive structure field register assignment.  */
+/* A subroutine of function_arg_record_value.  Assign the bits of the
+   structure between parms->intoffset and bitpos to integer registers.  */
 
 static void 
 function_arg_record_value_3 (bitpos, parms)
-     int bitpos;
+     HOST_WIDE_INT bitpos;
      struct function_arg_record_value_parms *parms;
 {
   enum machine_mode mode;
-  int regno, this_slotno, intslots, intoffset;
+  unsigned int regno;
+  unsigned int startbit, endbit;
+  int this_slotno, intslots, intoffset;
   rtx reg;
 
   if (parms->intoffset == -1)
     return;
+
   intoffset = parms->intoffset;
   parms->intoffset = -1;
 
-  intslots = (bitpos - intoffset + BITS_PER_WORD - 1) / BITS_PER_WORD;
+  startbit = intoffset & -BITS_PER_WORD;
+  endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
+  intslots = (endbit - startbit) / BITS_PER_WORD;
   this_slotno = parms->slotno + intoffset / BITS_PER_WORD;
 
   intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
@@ -3945,10 +4279,8 @@ function_arg_record_value_3 (bitpos, parms)
      at the moment but may wish to revisit.  */
 
   if (intoffset % BITS_PER_WORD != 0)
-    {
-      mode = mode_for_size (BITS_PER_WORD - intoffset%BITS_PER_WORD,
-                           MODE_INT, 0);
-    }
+    mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
+                         MODE_INT, 0);
   else
     mode = word_mode;
 
@@ -3968,10 +4300,15 @@ function_arg_record_value_3 (bitpos, parms)
   while (intslots > 0);
 }
 
+/* A subroutine of function_arg_record_value.  Traverse the structure
+   recursively and assign bits to floating point registers.  Track which
+   bits in between need integer registers; invoke function_arg_record_value_3
+   to make that happen.  */
+
 static void
 function_arg_record_value_2 (type, startbitpos, parms)
      tree type;
-     int startbitpos;
+     HOST_WIDE_INT startbitpos;
      struct function_arg_record_value_parms *parms;
 {
   tree field;
@@ -3990,15 +4327,16 @@ function_arg_record_value_2 (type, startbitpos, parms)
     {
       if (TREE_CODE (field) == FIELD_DECL)
        {
-         int bitpos = startbitpos;
-         if (DECL_FIELD_BITPOS (field))
-           bitpos += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
+         HOST_WIDE_INT bitpos = startbitpos;
+
+         if (DECL_SIZE (field) != 0
+             && host_integerp (bit_position (field), 1))
+           bitpos += int_bit_position (field);
+
          /* ??? FIXME: else assume zero offset.  */
 
          if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
-           {
-             function_arg_record_value_2 (TREE_TYPE (field), bitpos, parms);
-           }
+           function_arg_record_value_2 (TREE_TYPE (field), bitpos, parms);
          else if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
                   && TARGET_FPU
                   && ! packed_p
@@ -4027,6 +4365,9 @@ function_arg_record_value_2 (type, startbitpos, parms)
     }
 }
 
+/* Used by function_arg and function_value to implement the complex
+   Sparc64 structure calling conventions.  */
+
 static rtx
 function_arg_record_value (type, mode, slotno, named, regbase)
      tree type;
@@ -4035,7 +4376,7 @@ function_arg_record_value (type, mode, slotno, named, regbase)
 {
   HOST_WIDE_INT typesize = int_size_in_bytes (type);
   struct function_arg_record_value_parms parms;
-  int nregs;
+  unsigned int nregs;
 
   parms.ret = NULL_RTX;
   parms.slotno = slotno;
@@ -4049,10 +4390,12 @@ function_arg_record_value (type, mode, slotno, named, regbase)
 
   if (parms.intoffset != -1)
     {
+      unsigned int startbit, endbit;
       int intslots, this_slotno;
 
-      intslots = (typesize*BITS_PER_UNIT - parms.intoffset + BITS_PER_WORD - 1)
-       / BITS_PER_WORD;
+      startbit = parms.intoffset & -BITS_PER_WORD;
+      endbit = (typesize*BITS_PER_UNIT + BITS_PER_WORD - 1) & -BITS_PER_WORD;
+      intslots = (endbit - startbit) / BITS_PER_WORD;
       this_slotno = slotno + parms.intoffset / BITS_PER_WORD;
 
       intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
@@ -4450,9 +4793,11 @@ function_value (type, mode, incoming_p)
 
          return function_arg_record_value (type, mode, 0, 1, regbase);
        }
-      else if (TREE_CODE (type) == UNION_TYPE)
+      else if (AGGREGATE_TYPE_P (type))
        {
-         int bytes = int_size_in_bytes (type);
+         /* All other aggregate types are passed in an integer register
+            in a mode corresponding to the size of the type.  */
+         HOST_WIDE_INT bytes = int_size_in_bytes (type);
 
          if (bytes > 32)
            abort ();
@@ -4464,7 +4809,7 @@ function_value (type, mode, incoming_p)
   if (TARGET_ARCH64
       && GET_MODE_CLASS (mode) == MODE_INT 
       && GET_MODE_SIZE (mode) < UNITS_PER_WORD
-      && type && TREE_CODE (type) != UNION_TYPE)
+      && type && ! AGGREGATE_TYPE_P (type))
     mode = DImode;
 
   if (incoming_p)
@@ -4488,17 +4833,18 @@ sparc_builtin_saveregs ()
 
   for (regno = first_reg; regno < NPARM_REGS (word_mode); regno++)
     emit_move_insn (gen_rtx_MEM (word_mode,
-                            gen_rtx_PLUS (Pmode,
-                                     frame_pointer_rtx,
-                                     GEN_INT (STACK_POINTER_OFFSET
-                                              + UNITS_PER_WORD * regno))),
+                                gen_rtx_PLUS (Pmode,
+                                              frame_pointer_rtx,
+                                              GEN_INT (STACK_POINTER_OFFSET
+                                                       + (UNITS_PER_WORD
+                                                          * regno)))),
                    gen_rtx_REG (word_mode,
-                            BASE_INCOMING_ARG_REG (word_mode) + regno));
+                                BASE_INCOMING_ARG_REG (word_mode) + regno));
 
   address = gen_rtx_PLUS (Pmode,
-                    frame_pointer_rtx,
-                    GEN_INT (STACK_POINTER_OFFSET
-                             + UNITS_PER_WORD * first_reg));
+                         frame_pointer_rtx,
+                         GEN_INT (STACK_POINTER_OFFSET
+                                  + UNITS_PER_WORD * first_reg));
 
   if (current_function_check_memory_usage
       && first_reg < NPARM_REGS (word_mode))
@@ -4542,7 +4888,7 @@ sparc_va_arg (valist, type)
 
   if (TARGET_ARCH64)
     {
-      if (TYPE_ALIGN (type) >= 2 * BITS_PER_WORD)
+      if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD)
        align = 2 * UNITS_PER_WORD;
 
       if (AGGREGATE_TYPE_P (type))
@@ -4565,12 +4911,6 @@ sparc_va_arg (valist, type)
          indirect = 1;
          size = rsize = UNITS_PER_WORD;
        }
-      else
-       {
-         /* ??? The old va-sparc.h implementation, for 8 byte objects
-            copied stuff to a temporary -- I don't see that that 
-            provides any more alignment than the stack slot did.  */
-       }
     }
 
   incr = valist;
@@ -4597,11 +4937,42 @@ sparc_va_arg (valist, type)
 
   addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL);
 
+  /* If the address isn't aligned properly for the type,
+     we may need to copy to a temporary.  
+     FIXME: This is inefficient.  Usually we can do this
+     in registers.  */
+  if (align == 0
+      && TYPE_ALIGN (type) > BITS_PER_WORD
+      && !indirect)
+    {
+      /* FIXME: We really need to specify that the temporary is live
+        for the whole function because expand_builtin_va_arg wants
+        the alias set to be get_varargs_alias_set (), but in this
+        case the alias set is that for TYPE and if the memory gets
+        reused it will be reused with alias set TYPE.  */
+      rtx tmp = assign_temp (type, 0, 1, 0);
+      rtx dest_addr;
+
+      addr_rtx = force_reg (Pmode, addr_rtx);
+      addr_rtx = gen_rtx_MEM (BLKmode, addr_rtx);
+      set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
+      set_mem_align (addr_rtx, BITS_PER_WORD);
+      tmp = shallow_copy_rtx (tmp);
+      PUT_MODE (tmp, BLKmode);
+      set_mem_alias_set (tmp, 0);
+      
+      dest_addr = emit_block_move (tmp, addr_rtx, GEN_INT (rsize));
+      if (dest_addr != NULL_RTX)
+       addr_rtx = dest_addr;
+      else
+       addr_rtx = XCEXP (tmp, 0, MEM);
+    }
+
   if (indirect)
     {
       addr_rtx = force_reg (Pmode, addr_rtx);
       addr_rtx = gen_rtx_MEM (Pmode, addr_rtx);
-      MEM_ALIAS_SET (addr_rtx) = get_varargs_alias_set ();
+      set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
     }
 
   return addr_rtx;
@@ -4820,8 +5191,7 @@ sparc_emit_float_lib_cmp (x, y, comparison)
      rtx x, y;
      enum rtx_code comparison;
 {
-  char *qpfunc;
-  rtx cmp = const0_rtx;
+  const char *qpfunc;
   rtx slot0, slot1, result, tem, tem2;
   enum machine_mode mode;
 
@@ -5165,9 +5535,9 @@ output_return (operands)
       else
        {
          if ((actual_fsize & 0x3ff) != 0)
-           return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
+           return "sethi\t%%hi(%a0), %%g1\n\tor\t%%g1, %%lo(%a0), %%g1\n\tretl\n\tadd\t%%sp, %%g1, %%sp";
          else
-           return "sethi %%hi(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
+           return "sethi\t%%hi(%a0), %%g1\n\tretl\n\tadd\t%%sp, %%g1, %%sp";
        }
     }
   else if (TARGET_V9)
@@ -5195,13 +5565,13 @@ output_return (operands)
 \f
 /* Leaf functions and non-leaf functions have different needs.  */
 
-static int
+static const int
 reg_leaf_alloc_order[] = REG_LEAF_ALLOC_ORDER;
 
-static int
+static const int
 reg_nonleaf_alloc_order[] = REG_ALLOC_ORDER;
 
-static int *reg_alloc_orders[] = {
+static const int *const reg_alloc_orders[] = {
   reg_leaf_alloc_order,
   reg_nonleaf_alloc_order};
 
@@ -5213,8 +5583,9 @@ order_regs_for_local_alloc ()
   if (regs_ever_live[15] != last_order_nonleaf)
     {
       last_order_nonleaf = !last_order_nonleaf;
-      bcopy ((char *) reg_alloc_orders[last_order_nonleaf],
-            (char *) reg_alloc_order, FIRST_PSEUDO_REGISTER * sizeof (int));
+      memcpy ((char *) reg_alloc_order,
+             (const char *) reg_alloc_orders[last_order_nonleaf],
+             FIRST_PSEUDO_REGISTER * sizeof (int));
     }
 }
 \f
@@ -5306,7 +5677,8 @@ int
 addrs_ok_for_ldd_peep (addr1, addr2)
       rtx addr1, addr2;
 {
-  int reg1, offset1;
+  unsigned int reg1;
+  int offset1;
 
   /* Extract a register number and offset (if used) from the first addr.  */
   if (GET_CODE (addr1) == PLUS)
@@ -5615,8 +5987,7 @@ print_operand (file, x, code)
     {
       fputc ('[', file);
        /* Poor Sun assembler doesn't understand absolute addressing.  */
-      if (CONSTANT_P (XEXP (x, 0))
-         && ! TARGET_LIVE_G0)
+      if (CONSTANT_P (XEXP (x, 0)))
        fputs ("%g0+", file);
       output_address (XEXP (x, 0));
       fputc (']', file);
@@ -6287,10 +6658,10 @@ sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op,
 \f
 /* Set up the stack and frame (if desired) for the function.  */
 
-void
-sparc_flat_output_function_prologue (file, size)
+static void
+sparc_flat_function_prologue (file, size)
      FILE *file;
-     int size;
+     HOST_WIDE_INT size;
 {
   const char *sp_str = reg_names[STACK_POINTER_REGNUM];
   unsigned long gmask = current_frame_info.gmask;
@@ -6331,8 +6702,8 @@ sparc_flat_output_function_prologue (file, size)
   if (size > 0)
     {
       unsigned int reg_offset = current_frame_info.reg_offset;
-      const char *fp_str = reg_names[FRAME_POINTER_REGNUM];
-      const char *t1_str = "%g1";
+      const char *const fp_str = reg_names[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
@@ -6346,25 +6717,27 @@ sparc_flat_output_function_prologue (file, size)
         the gdb folk first.  */
 
       /* Is the entire register save area offsettable from %sp?  */
-      if (reg_offset < 4096 - 64 * UNITS_PER_WORD)
+      if (reg_offset < 4096 - 64 * (unsigned) UNITS_PER_WORD)
        {
          if (size <= 4096)
            {
              fprintf (file, "\tadd\t%s, %d, %s\n",
-                      sp_str, -size, sp_str);
+                      sp_str, (int) -size, sp_str);
              if (gmask & FRAME_POINTER_MASK)
                {
                  fprintf (file, "\tst\t%s, [%s+%d]\n",
                           fp_str, sp_str, reg_offset);
                  fprintf (file, "\tsub\t%s, %d, %s\t%s# set up frame pointer\n",
-                          sp_str, -size, fp_str, ASM_COMMENT_START);
+                          sp_str, (int) -size, fp_str, ASM_COMMENT_START);
                  reg_offset += 4;
                }
            }
          else
            {
-             fprintf (file, "\tset\t%d, %s\n\tsub\t%s, %s, %s\n",
-                      size, t1_str, sp_str, t1_str, sp_str);
+             fprintf (file, "\tset\t");
+             fprintf (file, HOST_WIDE_INT_PRINT_DEC, size);
+             fprintf (file, ", %s\n\tsub\t%s, %s, %s\n",
+                      t1_str, sp_str, t1_str, sp_str);
              if (gmask & FRAME_POINTER_MASK)
                {
                  fprintf (file, "\tst\t%s, [%s+%d]\n",
@@ -6404,31 +6777,33 @@ sparc_flat_output_function_prologue (file, size)
          /* Subtract %sp in two steps, but make sure there is always a
             64 byte register save area, and %sp is properly aligned.  */
          /* Amount to decrement %sp by, the first time.  */
-         unsigned int size1 = ((size - reg_offset + 64) + 15) & -16;
+         unsigned HOST_WIDE_INT size1 = ((size - reg_offset + 64) + 15) & -16;
          /* Offset to register save area from %sp.  */
-         unsigned int offset = size1 - (size - reg_offset);
+         unsigned HOST_WIDE_INT offset = size1 - (size - reg_offset);
          
          if (size1 <= 4096)
            {
              fprintf (file, "\tadd\t%s, %d, %s\n",
-                      sp_str, -size1, sp_str);
+                      sp_str, (int) -size1, sp_str);
              if (gmask & FRAME_POINTER_MASK)
                {
                  fprintf (file, "\tst\t%s, [%s+%d]\n\tsub\t%s, %d, %s\t%s# set up frame pointer\n",
-                          fp_str, sp_str, offset, sp_str, -size1, fp_str,
-                          ASM_COMMENT_START);
+                          fp_str, sp_str, (int) offset, sp_str, (int) -size1,
+                          fp_str, ASM_COMMENT_START);
                  offset += 4;
                }
            }
          else
            {
-             fprintf (file, "\tset\t%d, %s\n\tsub\t%s, %s, %s\n",
-                      size1, t1_str, sp_str, t1_str, sp_str);
+             fprintf (file, "\tset\t");
+             fprintf (file, HOST_WIDE_INT_PRINT_DEC, size1);
+             fprintf (file, ", %s\n\tsub\t%s, %s, %s\n",
+                      t1_str, sp_str, t1_str, sp_str);
              if (gmask & 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);
+                          fp_str, sp_str, (int) offset, sp_str, t1_str,
+                          fp_str, ASM_COMMENT_START);
                  offset += 4;
                }
            }
@@ -6447,7 +6822,7 @@ sparc_flat_output_function_prologue (file, size)
          if (gmask & RETURN_ADDR_MASK)
            {
              fprintf (file, "\tst\t%s, [%s+%d]\n",
-                      reg_names[RETURN_ADDR_REGNUM], sp_str, offset);
+                      reg_names[RETURN_ADDR_REGNUM], sp_str, (int) offset);
              if (dwarf2out_do_frame ())
                /* offset - size1 == reg_offset - size
                   if reg_offset were updated above like offset.  */
@@ -6458,8 +6833,10 @@ sparc_flat_output_function_prologue (file, size)
                                   gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK),
                                   current_frame_info.fmask,
                                   "st", "std", -size1);
-         fprintf (file, "\tset\t%d, %s\n\tsub\t%s, %s, %s\n",
-                  size - size1, t1_str, sp_str, t1_str, sp_str);
+         fprintf (file, "\tset\t");
+         fprintf (file, HOST_WIDE_INT_PRINT_DEC, size - size1);
+         fprintf (file, ", %s\n\tsub\t%s, %s, %s\n",
+                  t1_str, sp_str, t1_str, sp_str);
          if (dwarf2out_do_frame ())
            if (! (gmask & FRAME_POINTER_MASK))
              dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, size);
@@ -6472,10 +6849,10 @@ sparc_flat_output_function_prologue (file, size)
 /* Do any necessary cleanup after a function to restore stack, frame,
    and regs. */
 
-void
-sparc_flat_output_function_epilogue (file, size)
+static void
+sparc_flat_function_epilogue (file, size)
      FILE *file;
-     int size;
+     HOST_WIDE_INT size;
 {
   rtx epilogue_delay = current_function_epilogue_delay_list;
   int noepilogue = FALSE;
@@ -6507,18 +6884,22 @@ sparc_flat_output_function_epilogue (file, size)
 
   if (!noepilogue)
     {
-      unsigned int reg_offset = current_frame_info.reg_offset;
-      unsigned int size1;
-      const char *sp_str = reg_names[STACK_POINTER_REGNUM];
-      const char *fp_str = reg_names[FRAME_POINTER_REGNUM];
-      const char *t1_str = "%g1";
+      unsigned HOST_WIDE_INT reg_offset = current_frame_info.reg_offset;
+      unsigned HOST_WIDE_INT size1;
+      const char *const sp_str = reg_names[STACK_POINTER_REGNUM];
+      const char *const fp_str = reg_names[FRAME_POINTER_REGNUM];
+      static const char *const t1_str = "%g1";
 
       /* In the reload sequence, we don't need to fill the load delay
         slots for most of the loads, also see if we can fill the final
         delay slot if not otherwise filled by the reload sequence.  */
 
       if (size > 4095)
-       fprintf (file, "\tset\t%d, %s\n", size, t1_str);
+        {
+         fprintf (file, "\tset\t");
+         fprintf (file, HOST_WIDE_INT_PRINT_DEC, size);
+         fprintf (file, ", %s\n", t1_str);
+       }
 
       if (frame_pointer_needed)
        {
@@ -6527,11 +6908,11 @@ sparc_flat_output_function_epilogue (file, size)
                     fp_str, t1_str, sp_str, ASM_COMMENT_START);
          else
            fprintf (file,"\tsub\t%s, %d, %s\t\t%s# sp not trusted here\n",
-                    fp_str, size, sp_str, ASM_COMMENT_START);
+                    fp_str, (int) size, sp_str, ASM_COMMENT_START);
        }
 
       /* Is the entire register save area offsettable from %sp?  */
-      if (reg_offset < 4096 - 64 * UNITS_PER_WORD)
+      if (reg_offset < 4096 - 64 * (unsigned) UNITS_PER_WORD)
        {
          size1 = 0;
        }
@@ -6544,8 +6925,10 @@ sparc_flat_output_function_epilogue (file, size)
          /* Offset to register save area from %sp.  */
          reg_offset = size1 - reg_offset;
 
-         fprintf (file, "\tset\t%d, %s\n\tadd\t%s, %s, %s\n",
-                  size1, t1_str, sp_str, t1_str, sp_str);
+         fprintf (file, "\tset\t");
+         fprintf (file, HOST_WIDE_INT_PRINT_DEC, size1);
+         fprintf (file, ", %s\n\tadd\t%s, %s, %s\n",
+                  t1_str, sp_str, t1_str, sp_str);
        }
 
       /* We must restore the frame pointer and return address reg first
@@ -6553,13 +6936,13 @@ sparc_flat_output_function_epilogue (file, size)
       if (current_frame_info.gmask & FRAME_POINTER_MASK)
        {
          fprintf (file, "\tld\t[%s+%d], %s\n",
-                  sp_str, reg_offset, fp_str);
+                  sp_str, (int) reg_offset, fp_str);
          reg_offset += 4;
        }
       if (current_frame_info.gmask & RETURN_ADDR_MASK)
        {
          fprintf (file, "\tld\t[%s+%d], %s\n",
-                  sp_str, reg_offset, reg_names[RETURN_ADDR_REGNUM]);
+                  sp_str, (int) reg_offset, reg_names[RETURN_ADDR_REGNUM]);
          reg_offset += 4;
        }
 
@@ -6575,8 +6958,11 @@ sparc_flat_output_function_epilogue (file, size)
        {
          size -= size1;
          if (size > 4095)
-           fprintf (file, "\tset\t%d, %s\n",
-                    size, t1_str);
+           {
+             fprintf (file, "\tset\t");
+             fprintf (file, HOST_WIDE_INT_PRINT_DEC, size);
+             fprintf (file, ", %s\n", t1_str);
+           }
        }
 
       if (current_function_returns_struct)
@@ -6600,7 +6986,7 @@ sparc_flat_output_function_epilogue (file, size)
        fprintf (file, "\tadd\t%s, %s, %s\n", sp_str, t1_str, sp_str);
 
       else if (size > 0)
-       fprintf (file, "\tadd\t%s, %d, %s\n", sp_str, size, sp_str);
+       fprintf (file, "\tadd\t%s, %d, %s\n", sp_str, (int) size, sp_str);
 
       else
        fprintf (file, "\tnop\n");
@@ -6629,7 +7015,7 @@ sparc_flat_epilogue_delay_slots ()
   return 0;
 }
 
-/* Return true is TRIAL is a valid insn for the epilogue delay slot.
+/* 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.  */
 
@@ -6643,12 +7029,6 @@ sparc_flat_eligible_for_epilogue_delay (trial, slot)
   if (get_attr_length (trial) != 1)
     return 0;
 
-  /* If %g0 is live, there are lots of things we can't handle.
-     Rather than trying to find them all now, let's punt and only
-     optimize things as necessary.  */
-  if (TARGET_LIVE_G0)
-    return 0;
-
   if (! reg_mentioned_p (stack_pointer_rtx, pat)
       && ! reg_mentioned_p (frame_pointer_rtx, pat))
     return 1;
@@ -6907,8 +7287,7 @@ ultrasparc_adjust_cost (insn, link, dep_insn, cost)
             or the cycle after an instruction which writes any
             integer register.  Model this as cost 2 for dependent
             instructions.  */
-         if ((dep_type == TYPE_IALU || dep_type == TYPE_UNARY
-              || dep_type == TYPE_BINARY)
+         if (dep_type == TYPE_IALU
              && cost < 2)
            return 2;
          /* Otherwise check as for integer conditional moves. */
@@ -6957,7 +7336,7 @@ ultrasparc_adjust_cost (insn, link, dep_insn, cost)
 #undef SLOW_FP
 }
 
-int
+static int
 sparc_adjust_cost(insn, link, dep, cost)
      rtx insn;
      rtx link;
@@ -7002,7 +7381,7 @@ enum ultra_code { NONE=0, /* no insn at all                               */
 static enum ultra_code ultra_code_from_mask PARAMS ((int));
 static void ultra_schedule_insn PARAMS ((rtx *, rtx *, int, enum ultra_code));
 
-static const char *ultra_code_names[NUM_ULTRA_CODES] = {
+static const char *const ultra_code_names[NUM_ULTRA_CODES] = {
   "NONE", "IEU0", "IEU1", "IEUN", "LSU", "CTI",
   "FPM", "FPA", "SINGLE" };
 
@@ -7046,10 +7425,10 @@ ultra_code_from_mask (type_mask)
     return IEU0;
   else if (type_mask & (TMASK (TYPE_COMPARE) |
                        TMASK (TYPE_CALL) |
+                       TMASK (TYPE_SIBCALL) |
                        TMASK (TYPE_UNCOND_BRANCH)))
     return IEU1;
-  else if (type_mask & (TMASK (TYPE_IALU) | TMASK (TYPE_BINARY) |
-                       TMASK (TYPE_MOVE) | TMASK (TYPE_UNARY)))
+  else if (type_mask & TMASK (TYPE_IALU))
     return IEUN;
   else if (type_mask & (TMASK (TYPE_LOAD) | TMASK (TYPE_SLOAD) |
                        TMASK (TYPE_STORE) | TMASK (TYPE_FPLOAD) |
@@ -7130,7 +7509,7 @@ ultra_fpmode_conflict_exists (fpmode)
            continue;
 
          /* If it is not FMOV, FABS, FNEG, FDIV, or FSQRT then
-            we will get a stall.  Loads and stores are independant
+            we will get a stall.  Loads and stores are independent
             of these rules.  */
          if (GET_CODE (SET_SRC (pat)) != ABS
              && GET_CODE (SET_SRC (pat)) != NEG
@@ -7221,8 +7600,8 @@ ultra_find_type (type_mask, list, start)
                                  && GET_CODE (SET_SRC (pat)) == SUBREG
                                  && REGNO (SUBREG_REG (SET_DEST (slot_pat))) ==
                                       REGNO (SUBREG_REG (SET_SRC (pat)))
-                                 && SUBREG_WORD (SET_DEST (slot_pat)) ==
-                                      SUBREG_WORD (SET_SRC (pat)))))
+                                 && SUBREG_BYTE (SET_DEST (slot_pat)) ==
+                                      SUBREG_BYTE (SET_SRC (pat)))))
                      || (check_fpmode_conflict == 1
                          && GET_CODE (slot_insn) == INSN
                          && GET_CODE (slot_pat) == SET
@@ -7332,26 +7711,34 @@ ultra_flush_pipeline ()
 {
   ultra_cur_hist = (ultra_cur_hist + 1) & (ULTRA_NUM_HIST - 1);
   ultra_cycles_elapsed += 1;
-  bzero ((char *) &ultra_pipe, sizeof ultra_pipe);
+  memset ((char *) &ultra_pipe, 0, sizeof ultra_pipe);
   ultra_pipe.free_slot_mask = 0xf;
 }
 
 /* Init our data structures for this current block.  */
-void
-ultrasparc_sched_init (dump, sched_verbose)
-     FILE *dump ATTRIBUTE_UNUSED;
-     int sched_verbose ATTRIBUTE_UNUSED;
+static void
+ultrasparc_sched_init ()
 {
-  bzero ((char *) ultra_pipe_hist, sizeof ultra_pipe_hist);
+  memset ((char *) ultra_pipe_hist, 0, sizeof ultra_pipe_hist);
   ultra_cur_hist = 0;
   ultra_cycles_elapsed = 0;
   ultra_pipe.free_slot_mask = 0xf;
 }
 
+static void
+sparc_sched_init (dump, sched_verbose, max_ready)
+     FILE *dump ATTRIBUTE_UNUSED;
+     int sched_verbose ATTRIBUTE_UNUSED;
+     int max_ready ATTRIBUTE_UNUSED;
+{
+  if (sparc_cpu == PROCESSOR_ULTRASPARC)
+    ultrasparc_sched_init ();
+}
+  
 /* INSN has been scheduled, update pipeline commit state
    and return how many instructions are still to be
    scheduled in this group.  */
-int
+static int
 ultrasparc_variable_issue (insn)
      rtx insn;
 {
@@ -7375,6 +7762,19 @@ ultrasparc_variable_issue (insn)
   return left_to_fire;
 }
 
+static int
+sparc_variable_issue (dump, sched_verbose, insn, cim)
+     FILE *dump ATTRIBUTE_UNUSED;
+     int sched_verbose ATTRIBUTE_UNUSED;
+     rtx insn;
+     int cim;
+{
+  if (sparc_cpu == PROCESSOR_ULTRASPARC)
+    return ultrasparc_variable_issue (insn);
+  else
+    return cim - 1;
+}
+
 /* In actual_hazard_this_instance, we may have yanked some
    instructions from the ready list due to conflict cost
    adjustments.  If so, and such an insn was in our pipeline
@@ -7424,7 +7824,7 @@ ultra_rescan_pipeline_state (ready, n_ready)
     }
 }
 
-void
+static void
 ultrasparc_sched_reorder (dump, sched_verbose, ready, n_ready)
      FILE *dump;
      int sched_verbose;
@@ -7505,7 +7905,7 @@ ultrasparc_sched_reorder (dump, sched_verbose, ready, n_ready)
       {
        /* If the pipeline is (still) empty and we have any single
           group insns, get them out now as this is a good time.  */
-       rtx *ip = ultra_find_type ((TMASK (TYPE_RETURN) | TMASK (TYPE_ADDRESS) |
+       rtx *ip = ultra_find_type ((TMASK (TYPE_RETURN) |
                                    TMASK (TYPE_IMUL) | TMASK (TYPE_CMOVE) |
                                    TMASK (TYPE_MULTI) | TMASK (TYPE_MISC)),
                                   ready, this_insn);
@@ -7518,6 +7918,7 @@ ultrasparc_sched_reorder (dump, sched_verbose, ready, n_ready)
        /* If we are not in the process of emptying out the pipe, try to
           obtain an instruction which must be the first in it's group.  */
        ip = ultra_find_type ((TMASK (TYPE_CALL) |
+                              TMASK (TYPE_SIBCALL) |
                               TMASK (TYPE_CALL_NO_DELAY_SLOT) |
                               TMASK (TYPE_UNCOND_BRANCH)),
                              ready, this_insn);
@@ -7558,8 +7959,7 @@ ultrasparc_sched_reorder (dump, sched_verbose, ready, n_ready)
     if ((up->free_slot_mask & 0x7) != 0
        && up->num_ieu_insns < 2)
       {
-       rtx *ip = ultra_find_type ((TMASK (TYPE_IALU) | TMASK (TYPE_BINARY) |
-                                   TMASK (TYPE_MOVE) | TMASK (TYPE_UNARY) |
+       rtx *ip = ultra_find_type ((TMASK (TYPE_IALU) |
                                    (up->contents[IEU1] == 0 ? TMASK (TYPE_COMPARE) : 0)),
                                   ready, this_insn);
        if (ip)
@@ -7580,8 +7980,7 @@ ultrasparc_sched_reorder (dump, sched_verbose, ready, n_ready)
        && up->num_ieu_insns < 2)
       {
        rtx *ip;
-       int tmask = (TMASK (TYPE_IALU) | TMASK (TYPE_BINARY) |
-                    TMASK (TYPE_MOVE) | TMASK (TYPE_UNARY));
+       int tmask = TMASK (TYPE_IALU);
 
        if (!up->contents[IEU1])
          tmask |= TMASK (TYPE_COMPARE);
@@ -7677,7 +8076,7 @@ ultrasparc_sched_reorder (dump, sched_verbose, ready, n_ready)
       }
     else
       {
-       bzero ((char *) &ultra_pipe, sizeof ultra_pipe);
+       memset ((char *) &ultra_pipe, 0, sizeof ultra_pipe);
        ultra_pipe.free_slot_mask = 0xf;
       }
   }
@@ -7709,7 +8108,20 @@ ultrasparc_sched_reorder (dump, sched_verbose, ready, n_ready)
     }
 }
 
-int                                                           
+static int
+sparc_sched_reorder (dump, sched_verbose, ready, n_readyp, clock)
+     FILE *dump;
+     int sched_verbose;
+     rtx *ready;
+     int *n_readyp;
+     int clock ATTRIBUTE_UNUSED;
+{
+  if (sparc_cpu == PROCESSOR_ULTRASPARC)
+    ultrasparc_sched_reorder (dump, sched_verbose, ready, *n_readyp);
+  return sparc_issue_rate ();
+}
+
+static int                                                           
 sparc_issue_rate ()
 {
   switch (sparc_cpu)
@@ -7730,8 +8142,8 @@ sparc_issue_rate ()
 }
 
 static int
-set_extends(x, insn)
-     rtx x, insn;
+set_extends (insn)
+     rtx insn;
 {
   register rtx pat = PATTERN (insn);
 
@@ -7755,27 +8167,40 @@ set_extends(x, insn)
       return 1;
     case AND:
       {
+       rtx op0 = XEXP (SET_SRC (pat), 0);
        rtx op1 = XEXP (SET_SRC (pat), 1);
        if (GET_CODE (op1) == CONST_INT)
          return INTVAL (op1) >= 0;
-       if (GET_CODE (XEXP (SET_SRC (pat), 0)) == REG
-           && sparc_check_64 (XEXP (SET_SRC (pat), 0), insn) == 1)
-         return 1;
-       if (GET_CODE (op1) == REG
-           && sparc_check_64 ((op1), insn) == 1)
+       if (GET_CODE (op0) != REG)
+         return 0;
+       if (sparc_check_64 (op0, insn) == 1)
          return 1;
+       return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
+      }
+    case IOR:
+    case XOR:
+      {
+       rtx op0 = XEXP (SET_SRC (pat), 0);
+       rtx op1 = XEXP (SET_SRC (pat), 1);
+       if (GET_CODE (op0) != REG || sparc_check_64 (op0, insn) <= 0)
+         return 0;
+       if (GET_CODE (op1) == CONST_INT)
+         return INTVAL (op1) >= 0;
+       return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
       }
     case ASHIFT:
     case LSHIFTRT:
       return GET_MODE (SET_SRC (pat)) == SImode;
       /* Positive integers leave the high bits zero. */
     case CONST_DOUBLE:
-      return ! (CONST_DOUBLE_LOW (x) & 0x80000000);
+      return ! (CONST_DOUBLE_LOW (SET_SRC (pat)) & 0x80000000);
     case CONST_INT:
-      return ! (INTVAL (x) & 0x80000000);
+      return ! (INTVAL (SET_SRC (pat)) & 0x80000000);
     case ASHIFTRT:
     case SIGN_EXTEND:
       return - (GET_MODE (SET_SRC (pat)) == SImode);
+    case REG:
+      return sparc_check_64 (SET_SRC (pat), insn);
     default:
       return 0;
     }
@@ -7897,10 +8322,16 @@ sparc_check_64 (x, insn)
      the single set and return the correct value or fail to recognize
      it and return 0.  */
   int set_once = 0;
+  rtx y = x;
+
+  if (GET_CODE (x) != REG)
+    abort ();
+
+  if (GET_MODE (x) == DImode)
+    y = gen_rtx_REG (SImode, REGNO (x) + WORDS_BIG_ENDIAN);
 
-  if (GET_CODE (x) == REG
-      && flag_expensive_optimizations
-      && REG_N_SETS (REGNO (x)) == 1)
+  if (flag_expensive_optimizations
+      && REG_N_SETS (REGNO (y)) == 1)
     set_once = 1;
 
   if (insn == 0)
@@ -7930,8 +8361,10 @@ sparc_check_64 (x, insn)
            if (GET_CODE (pat) != SET)
              return 0;
            if (rtx_equal_p (x, SET_DEST (pat)))
-             return set_extends (x, insn);
-           if (reg_overlap_mentioned_p (SET_DEST (pat), x))
+             return set_extends (insn);
+           if (y && rtx_equal_p (y, SET_DEST (pat)))
+             return set_extends (insn);
+           if (reg_overlap_mentioned_p (SET_DEST (pat), y))
              return 0;
          }
        }
@@ -7951,21 +8384,21 @@ sparc_v8plus_shift (operands, insn, opcode)
     operands[3] = operands[0];
   if (GET_CODE (operands[1]) == CONST_INT)
     {
-      output_asm_insn ("mov %1,%3", operands);
+      output_asm_insn ("mov\t%1, %3", operands);
     }
   else
     {
-      output_asm_insn ("sllx %H1,32,%3", operands);
+      output_asm_insn ("sllx\t%H1, 32, %3", operands);
       if (sparc_check_64 (operands[1], insn) <= 0)
-       output_asm_insn ("srl %L1,0,%L1", operands);
-      output_asm_insn ("or %L1,%3,%3", operands);
+       output_asm_insn ("srl\t%L1, 0, %L1", operands);
+      output_asm_insn ("or\t%L1, %3, %3", operands);
     }
 
   strcpy(asm_code, opcode);
   if (which_alternative != 2)
-    return strcat (asm_code, " %0,%2,%L0\n\tsrlx %L0,32,%H0");
+    return strcat (asm_code, "\t%0, %2, %L0\n\tsrlx\t%L0, 32, %H0");
   else
-    return strcat (asm_code, " %3,%2,%3\n\tsrlx %3,32,%H0\n\tmov %3,%L0");
+    return strcat (asm_code, "\t%3, %2, %3\n\tsrlx\t%3, 32, %H0\n\tmov\t%3, %L0");
 }
 
 
@@ -8002,22 +8435,22 @@ sparc_function_profiler (file, labelno)
   ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
 
   if (! TARGET_ARCH64)
-    fputs ("\tst\t%g2,[%fp-4]\n", file);
+    fputs ("\tst\t%g2, [%fp-4]\n", file);
 
   fputs ("\tsethi\t%hi(", file);
   assemble_name (file, buf);
-  fputs ("),%o0\n", file);
+  fputs ("), %o0\n", file);
 
   fputs ("\tcall\t", file);
   assemble_name (file, MCOUNT_FUNCTION);
   putc ('\n', file);
 
-  fputs ("\t or\t%o0,%lo(", file);
+  fputs ("\t or\t%o0, %lo(", file);
   assemble_name (file, buf);
-  fputs ("),%o0\n", file);
+  fputs ("), %o0\n", file);
 
   if (! TARGET_ARCH64)
-    fputs ("\tld\t[%fp-4],%g2\n", file);
+    fputs ("\tld\t[%fp-4], %g2\n", file);
 }
 
 
@@ -8089,17 +8522,17 @@ sparc_function_block_profiler(file, block_or_label)
     {
       fputs ("\tsethi\t%hi(", file);
       assemble_name (file, LPBX);
-      fputs ("),%o0\n", file);
+      fputs ("), %o0\n", file);
   
-      fprintf (file, "\tsethi\t%%hi(%d),%%o1\n", block_or_label);
+      fprintf (file, "\tsethi\t%%hi(%d), %%o1\n", block_or_label);
 
-      fputs ("\tor\t%o0,%lo(", file);
+      fputs ("\tor\t%o0, %lo(", file);
       assemble_name (file, LPBX);
-      fputs ("),%o0\n", file);
+      fputs ("), %o0\n", file);
   
       fprintf (file, "\tcall\t%s__bb_init_trace_func\n", user_label_prefix);
 
-      fprintf (file, "\t or\t%%o1,%%lo(%d),%%o1\n", block_or_label);
+      fprintf (file, "\t or\t%%o1, %%lo(%d), %%o1\n", block_or_label);
     }
   else if (profile_block_flag != 0)
     {
@@ -8108,11 +8541,11 @@ sparc_function_block_profiler(file, block_or_label)
 
       fputs ("\tsethi\t%hi(", file);
       assemble_name (file, LPBX);
-      fputs ("),%o0\n", file);
+      fputs ("), %o0\n", file);
       
       fputs ("\tld\t[%lo(", file);
       assemble_name (file, LPBX);
-      fputs (")+%o0],%o1\n", file);
+      fputs (")+%o0], %o1\n", file);
 
       fputs ("\ttst\t%o1\n", file);
 
@@ -8129,9 +8562,9 @@ sparc_function_block_profiler(file, block_or_label)
          putc ('\n', file);
        }
 
-      fputs ("\t or\t%o0,%lo(", file);
+      fputs ("\t or\t%o0, %lo(", file);
       assemble_name (file, LPBX);
-      fputs ("),%o0\n", file);
+      fputs ("), %o0\n", file);
 
       fprintf (file, "\tcall\t%s__bb_init_func\n\t nop\n", user_label_prefix);
 
@@ -8216,27 +8649,27 @@ sparc_block_profiler(file, blockno)
     {
       ASM_GENERATE_INTERNAL_LABEL (LPBX, "LPBX", 0);
 
-      fprintf (file, "\tsethi\t%%hi(%s__bb),%%g1\n", user_label_prefix);
-      fprintf (file, "\tsethi\t%%hi(%d),%%g%d\n", blockno, bbreg);
-      fprintf (file, "\tor\t%%g1,%%lo(%s__bb),%%g1\n", user_label_prefix);
-      fprintf (file, "\tor\t%%g%d,%%lo(%d),%%g%d\n", bbreg, blockno, bbreg);
+      fprintf (file, "\tsethi\t%%hi(%s__bb), %%g1\n", user_label_prefix);
+      fprintf (file, "\tsethi\t%%hi(%d), %%g%d\n", blockno, bbreg);
+      fprintf (file, "\tor\t%%g1, %%lo(%s__bb), %%g1\n", user_label_prefix);
+      fprintf (file, "\tor\t%%g%d, %%lo(%d), %%g%d\n", bbreg, blockno, bbreg);
 
-      fprintf (file, "\tst\t%%g%d,[%%g1]\n", bbreg);
+      fprintf (file, "\tst\t%%g%d, [%%g1]\n", bbreg);
 
       fputs ("\tsethi\t%hi(", file);
       assemble_name (file, LPBX);
-      fprintf (file, "),%%g%d\n", bbreg);
+      fprintf (file, "), %%g%d\n", bbreg);
   
-      fputs ("\tor\t%o2,%lo(", file);
+      fputs ("\tor\t%o2, %lo(", file);
       assemble_name (file, LPBX);
-      fprintf (file, "),%%g%d\n", bbreg);
+      fprintf (file, "), %%g%d\n", bbreg);
   
-      fprintf (file, "\tst\t%%g%d,[%%g1+4]\n", bbreg);
-      fprintf (file, "\tmov\t%%o7,%%g%d\n", bbreg);
+      fprintf (file, "\tst\t%%g%d, [%%g1 + 4]\n", bbreg);
+      fprintf (file, "\tmov\t%%o7, %%g%d\n", bbreg);
 
       fprintf (file, "\tcall\t%s__bb_trace_func\n\t nop\n", user_label_prefix);
 
-      fprintf (file, "\tmov\t%%g%d,%%o7\n", bbreg);
+      fprintf (file, "\tmov\t%%g%d, %%o7\n", bbreg);
     }
   else if (profile_block_flag != 0)
     {
@@ -8244,18 +8677,18 @@ sparc_block_profiler(file, blockno)
 
       fputs ("\tsethi\t%hi(", file);
       assemble_name (file, LPBX);
-      fprintf (file, "+%d),%%g1\n", blockno*4);
+      fprintf (file, "+%d), %%g1\n", blockno*4);
 
       fputs ("\tld\t[%g1+%lo(", file);
       assemble_name (file, LPBX);
       if (TARGET_ARCH64 && USE_AS_OFFSETABLE_LO10)
-       fprintf (file, ")+%d],%%g%d\n", blockno*4, bbreg);
+       fprintf (file, ")+%d], %%g%d\n", blockno*4, bbreg);
       else
-       fprintf (file, "+%d)],%%g%d\n", blockno*4, bbreg);
+       fprintf (file, "+%d)], %%g%d\n", blockno*4, bbreg);
 
-      fprintf (file, "\tadd\t%%g%d,1,%%g%d\n", bbreg, bbreg);
+      fprintf (file, "\tadd\t%%g%d, 1, %%g%d\n", bbreg, bbreg);
 
-      fprintf (file, "\tst\t%%g%d,[%%g1+%%lo(", bbreg);
+      fprintf (file, "\tst\t%%g%d, [%%g1+%%lo(", bbreg);
       assemble_name (file, LPBX);
       if (TARGET_ARCH64 && USE_AS_OFFSETABLE_LO10)
        fprintf (file, ")+%d]\n", blockno*4);
@@ -8324,8 +8757,33 @@ sparc_add_gc_roots ()
   ggc_add_rtx_root (&get_pc_symbol, 1);
   ggc_add_rtx_root (&sparc_addr_diff_list, 1);
   ggc_add_rtx_root (&sparc_addr_list, 1);
-  ggc_add_root (ultra_pipe_hist, 
-               sizeof (ultra_pipe_hist) / sizeof (ultra_pipe_hist[0]),
-               sizeof (ultra_pipe_hist[0]),
-               &mark_ultrasparc_pipeline_state);
+  ggc_add_root (ultra_pipe_hist, ARRAY_SIZE (ultra_pipe_hist),
+               sizeof (ultra_pipe_hist[0]), &mark_ultrasparc_pipeline_state);
+}
+
+static void
+sparc_elf_asm_named_section (name, flags)
+     const char *name;
+     unsigned int flags;
+{
+  if (flags & SECTION_MERGE)
+    {
+      /* entsize cannot be expressed in this section attributes
+        encoding style.  */
+      default_elf_asm_named_section (name, flags);
+      return;
+    }
+
+  fprintf (asm_out_file, "\t.section\t\"%s\"", name);
+
+  if (!(flags & SECTION_DEBUG))
+    fputs (",#alloc", asm_out_file);
+  if (flags & SECTION_WRITE)
+    fputs (",#write", asm_out_file);
+  if (flags & SECTION_CODE)
+    fputs (",#execinstr", asm_out_file);
+
+  /* ??? Handle SECTION_BSS.  */
+
+  fputc ('\n', asm_out_file);
 }