OSDN Git Service

* config/sparc/sparc.c (sparc_override_options): Do support different
[pf3gnuchains/gcc-fork.git] / gcc / config / sparc / sparc.c
index 54c0230..4e3dbe6 100644 (file)
@@ -1,5 +1,6 @@
 /* Subroutines for insn-output.c for Sun SPARC.
-   Copyright (C) 1987, 88, 89, 92-98, 1999 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.
@@ -63,6 +64,10 @@ Boston, MA 02111-1307, USA.  */
 static int apparent_fsize;
 static int actual_fsize;
 
+/* Number of live general or floating point registers needed to be saved
+   (as 4-byte quantities).  This is only done if TARGET_EPILOGUE.  */
+static int num_gfregs;
+
 /* Save the operands last given to a compare for use when we
    generate a scc or bcc insn.  */
 
@@ -94,6 +99,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.
@@ -104,34 +127,34 @@ char leaf_reg_remap[] =
 static const char *frame_base_name;
 static int frame_base_offset;
 
-static rtx pic_setup_code      PROTO((void));
-static void sparc_init_modes   PROTO((void));
-static int save_regs           PROTO((FILE *, int, int, const char *,
+static void sparc_init_modes   PARAMS ((void));
+static int save_regs           PARAMS ((FILE *, int, int, const char *,
                                       int, int, int));
-static int restore_regs                PROTO((FILE *, int, int, const char *, int, int));
-static void build_big_number   PROTO((FILE *, int, const char *));
-static int function_arg_slotno PROTO((const CUMULATIVE_ARGS *,
+static int restore_regs                PARAMS ((FILE *, int, int, const char *, int, int));
+static void build_big_number   PARAMS ((FILE *, int, const char *));
+static int function_arg_slotno PARAMS ((const CUMULATIVE_ARGS *,
                                       enum machine_mode, tree, int, int,
                                       int *, int *));
 
-static int supersparc_adjust_cost PROTO((rtx, rtx, rtx, int));
-static int hypersparc_adjust_cost PROTO((rtx, rtx, rtx, int));
-static int ultrasparc_adjust_cost PROTO((rtx, rtx, rtx, int));
-
-static void sparc_output_addr_vec PROTO((rtx));
-static void sparc_output_addr_diff_vec PROTO((rtx));
-static void sparc_output_deferred_case_vectors PROTO((void));
-static void sparc_add_gc_roots    PROTO ((void));
-static void mark_ultrasparc_pipeline_state PROTO ((void *));
-static int check_return_regs PROTO ((rtx));
-static void epilogue_renumber PROTO ((rtx *));
-static int ultra_cmove_results_ready_p PROTO ((rtx));
-static int ultra_fpmode_conflict_exists PROTO ((enum machine_mode));
-static rtx *ultra_find_type PROTO ((int, rtx *, int));
-static void ultra_build_types_avail PROTO ((rtx *, int));
-static void ultra_flush_pipeline PROTO ((void));
-static void ultra_rescan_pipeline_state PROTO ((rtx *, int));
-static int set_extends PROTO ((rtx, rtx));
+static int supersparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
+static int hypersparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
+static int ultrasparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
+
+static void sparc_output_addr_vec PARAMS ((rtx));
+static void sparc_output_addr_diff_vec PARAMS ((rtx));
+static void sparc_output_deferred_case_vectors PARAMS ((void));
+static void sparc_add_gc_roots    PARAMS ((void));
+static void mark_ultrasparc_pipeline_state PARAMS ((void *));
+static int check_return_regs PARAMS ((rtx));
+static int epilogue_renumber PARAMS ((rtx *, int));
+static int ultra_cmove_results_ready_p PARAMS ((rtx));
+static int ultra_fpmode_conflict_exists PARAMS ((enum machine_mode));
+static rtx *ultra_find_type PARAMS ((int, rtx *, int));
+static void ultra_build_types_avail PARAMS ((rtx *, int));
+static void ultra_flush_pipeline PARAMS ((void));
+static void ultra_rescan_pipeline_state PARAMS ((rtx *, int));
+static int set_extends PARAMS ((rtx));
+static void output_restore_regs PARAMS ((FILE *, int));
 \f
 /* Option handling.  */
 
@@ -218,7 +241,7 @@ 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;
@@ -228,21 +251,15 @@ sparc_override_options ()
 #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.  */
@@ -311,6 +328,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;
@@ -323,10 +350,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;
@@ -339,7 +362,7 @@ sparc_override_options ()
   sparc_init_modes ();
 
   if ((profile_flag || profile_block_flag)
-      && sparc_cmodel != CM_MEDLOW)
+      && sparc_cmodel != CM_32 && sparc_cmodel != CM_MEDLOW)
     {
       error ("profiling does not support code models other than medlow");
     }
@@ -365,8 +388,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)
@@ -375,17 +397,13 @@ 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
       && CONST_DOUBLE_HIGH (op) == 0
       && CONST_DOUBLE_LOW (op) == 0)
     return 1;
-  if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
-      && GET_CODE (op) == CONST_DOUBLE
-      && fp_zero_operand (op))
+  if (fp_zero_operand (op, mode))
     return 1;
   return 0;
 }
@@ -393,13 +411,92 @@ reg_or_0_operand (op, mode)
 /* Nonzero if OP is a floating point value with value 0.0.  */
 
 int
-fp_zero_operand (op)
+fp_zero_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (GET_MODE_CLASS (GET_MODE (op)) != MODE_FLOAT)
+    return 0;
+  return op == CONST0_RTX (mode);
+}
+
+/* Nonzero if OP is a floating point constant which can
+   be loaded into an integer register using a single
+   sethi instruction.  */
+
+int
+fp_sethi_p (op)
      rtx op;
 {
-  REAL_VALUE_TYPE r;
+  if (GET_CODE (op) == CONST_DOUBLE)
+    {
+      REAL_VALUE_TYPE r;
+      long i;
 
-  REAL_VALUE_FROM_CONST_DOUBLE (r, op);
-  return (REAL_VALUES_EQUAL (r, dconst0) && ! REAL_VALUE_MINUS_ZERO (r));
+      REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+      if (REAL_VALUES_EQUAL (r, dconst0) &&
+         ! REAL_VALUE_MINUS_ZERO (r))
+       return 0;
+      REAL_VALUE_TO_TARGET_SINGLE (r, i);
+      if (SPARC_SETHI_P (i))
+       return 1;
+    }
+
+  return 0;
+}
+
+/* Nonzero if OP is a floating point constant which can
+   be loaded into an integer register using a single
+   mov instruction.  */
+
+int
+fp_mov_p (op)
+     rtx op;
+{
+  if (GET_CODE (op) == CONST_DOUBLE)
+    {
+      REAL_VALUE_TYPE r;
+      long i;
+
+      REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+      if (REAL_VALUES_EQUAL (r, dconst0) &&
+         ! REAL_VALUE_MINUS_ZERO (r))
+       return 0;
+      REAL_VALUE_TO_TARGET_SINGLE (r, i);
+      if (SPARC_SIMM13_P (i))
+       return 1;
+    }
+
+  return 0;
+}
+
+/* Nonzero if OP is a floating point constant which can
+   be loaded into an integer register using a high/losum
+   instruction sequence.  */
+
+int
+fp_high_losum_p (op)
+     rtx op;
+{
+  /* The constraints calling this should only be in
+     SFmode move insns, so any constant which cannot
+     be moved using a single insn will do.  */
+  if (GET_CODE (op) == CONST_DOUBLE)
+    {
+      REAL_VALUE_TYPE r;
+      long i;
+
+      REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+      if (REAL_VALUES_EQUAL (r, dconst0) &&
+         ! REAL_VALUE_MINUS_ZERO (r))
+       return 0;
+      REAL_VALUE_TO_TARGET_SINGLE (r, i);
+      if (! SPARC_SETHI_P (i)
+          && ! SPARC_SIMM13_P (i))
+       return 1;
+    }
+
+  return 0;
 }
 
 /* Nonzero if OP is an integer register.  */
@@ -1043,16 +1140,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
@@ -1075,7 +1162,9 @@ input_operand (op, mode)
           && ((SPARC_SETHI_P (INTVAL (op))
                && (! TARGET_ARCH64
                    || (INTVAL (op) >= 0)
-                   || mode == SImode))
+                   || mode == SImode
+                   || mode == HImode
+                   || mode == QImode))
               || SPARC_SIMM13_P (INTVAL (op))
               || (mode == DImode
                   && ! TARGET_ARCH64)))
@@ -1091,7 +1180,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;
@@ -1106,6 +1196,10 @@ input_operand (op, mode)
   if (register_operand (op, mode))
     return 1;
 
+  if (GET_MODE_CLASS (mode) == MODE_FLOAT
+      && GET_CODE (op) == CONST_DOUBLE)
+    return 1;
+
   /* If this is a SUBREG, look inside so that we handle
      paradoxical ones.  */
   if (GET_CODE (op) == SUBREG)
@@ -1332,10 +1426,10 @@ sparc_emit_set_symbolic_const64 (op0, op1, temp1)
 /* These avoid problems when cross compiling.  If we do not
    go through all this hair then the optimizer will see
    invalid REG_EQUAL notes or in some cases none at all.  */
-static void sparc_emit_set_safe_HIGH64 PROTO ((rtx, HOST_WIDE_INT));
-static rtx gen_safe_SET64 PROTO ((rtx, HOST_WIDE_INT));
-static rtx gen_safe_OR64 PROTO ((rtx, HOST_WIDE_INT));
-static rtx gen_safe_XOR64 PROTO ((rtx, HOST_WIDE_INT));
+static void sparc_emit_set_safe_HIGH64 PARAMS ((rtx, HOST_WIDE_INT));
+static rtx gen_safe_SET64 PARAMS ((rtx, HOST_WIDE_INT));
+static rtx gen_safe_OR64 PARAMS ((rtx, HOST_WIDE_INT));
+static rtx gen_safe_XOR64 PARAMS ((rtx, HOST_WIDE_INT));
 
 #if HOST_BITS_PER_WIDE_INT == 64
 #define GEN_HIGHINT64(__x)             GEN_INT ((__x) & 0xfffffc00)
@@ -1397,7 +1491,7 @@ gen_safe_XOR64 (src, val)
    opportunities.  */
 
 static void sparc_emit_set_const64_quick1
-       PROTO((rtx, rtx, unsigned HOST_WIDE_INT, int));
+       PARAMS ((rtx, rtx, unsigned HOST_WIDE_INT, int));
 
 static void
 sparc_emit_set_const64_quick1 (op0, temp, low_bits, is_neg)
@@ -1439,7 +1533,7 @@ sparc_emit_set_const64_quick1 (op0, temp, low_bits, is_neg)
 }
 
 static void sparc_emit_set_const64_quick2
-       PROTO((rtx, rtx, unsigned HOST_WIDE_INT,
+       PARAMS ((rtx, rtx, unsigned HOST_WIDE_INT,
               unsigned HOST_WIDE_INT, int));
 
 static void
@@ -1480,7 +1574,7 @@ sparc_emit_set_const64_quick2 (op0, temp, high_bits, low_immediate, shift_count)
 }
 
 static void sparc_emit_set_const64_longway
-       PROTO((rtx, rtx, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT));
+       PARAMS ((rtx, rtx, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT));
 
 /* Full 64-bit constant decomposition.  Even though this is the
    'worst' case, we still optimize a few things away.  */
@@ -1588,7 +1682,7 @@ sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits)
 
 /* Analyze a 64-bit constant for certain properties. */
 static void analyze_64bit_constant
-       PROTO((unsigned HOST_WIDE_INT,
+       PARAMS ((unsigned HOST_WIDE_INT,
               unsigned HOST_WIDE_INT,
               int *, int *, int *));
 
@@ -1657,7 +1751,7 @@ analyze_64bit_constant (high_bits, low_bits, hbsp, lbsp, abbasp)
 }
 
 static int const64_is_2insns
-       PROTO((unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT));
+       PARAMS ((unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT));
 
 static int
 const64_is_2insns (high_bits, low_bits)
@@ -1685,7 +1779,7 @@ const64_is_2insns (high_bits, low_bits)
 }
 
 static unsigned HOST_WIDE_INT create_simple_focus_bits
-       PROTO((unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
+       PARAMS ((unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
               int, int));
 
 static unsigned HOST_WIDE_INT
@@ -1725,12 +1819,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
@@ -1983,6 +2082,61 @@ sparc_emit_set_const64 (op0, op1)
   sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits);
 }
 
+/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
+   return the mode to be used for the comparison.  For floating-point,
+   CCFP[E]mode is used.  CC_NOOVmode should be used when the first operand
+   is a PLUS, MINUS, NEG, or ASHIFT.  CCmode should be used when no special
+   processing is needed.  */
+
+enum machine_mode
+select_cc_mode (op, x, y)
+     enum rtx_code op;
+     rtx x;
+     rtx y ATTRIBUTE_UNUSED;
+{
+  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+    {
+      switch (op)
+       {
+       case EQ:
+       case NE:
+       case UNORDERED:
+       case ORDERED:
+       case UNLT:
+       case UNLE:
+       case UNGT:
+       case UNGE:
+       case UNEQ:
+       case LTGT:
+         return CCFPmode;
+
+       case LT:
+       case LE:
+       case GT:
+       case GE:
+         return CCFPEmode;
+
+       default:
+         abort ();
+       }
+    }
+  else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
+          || GET_CODE (x) == NEG || GET_CODE (x) == ASHIFT)
+    {
+      if (TARGET_ARCH64 && GET_MODE (x) == DImode)
+       return CCX_NOOVmode;
+      else
+       return CC_NOOVmode;
+    }
+  else
+    {
+      if (TARGET_ARCH64 && GET_MODE (x) == DImode)
+       return CCXmode;
+      else
+       return CCmode;
+    }
+}
+
 /* X and Y are two things to compare using CODE.  Emit the compare insn and
    return the rtx for the cc reg in the proper mode.  */
 
@@ -2175,6 +2329,22 @@ emit_v9_brxx_insn (code, op0, label)
                                    gen_rtx_LABEL_REF (VOIDmode, label),
                                    pc_rtx)));
 }
+
+/* Generate a DFmode part of a hard TFmode register.
+   REG is the TFmode hard register, LOW is 1 for the
+   low 64bit of the register and 0 otherwise.
+ */
+rtx
+gen_df_reg (reg, low)
+     rtx reg;
+     int low;
+{
+  int regno = REGNO (reg);
+
+  if ((WORDS_BIG_ENDIAN == 0) ^ (low != 0))
+    regno += (TARGET_ARCH64 && regno < 32) ? 1 : 2;
+  return gen_rtx_REG (DFmode, regno);
+}
 \f
 /* Return nonzero if a return peephole merging return with
    setting of output register is ok.  */
@@ -2203,10 +2373,9 @@ 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)
+  /* 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;
 
   /* In the case of a true leaf function, anything can go into the delay slot.
@@ -2220,20 +2389,25 @@ 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' insn can go into the delay slot.  */
+     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.  */
 
@@ -2247,7 +2421,7 @@ eligible_for_epilogue_delay (trial, slot)
       else
         return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
     }
-    
+
   /* This matches "*return_di".  */
   else if (arith_double_operand (src, GET_MODE (src)))
     return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
@@ -2257,6 +2431,12 @@ eligible_for_epilogue_delay (trial, slot)
           && register_operand (src, SFmode))
     return 1;
 
+  /* If we have 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))
+    return 1;
+
   /* This matches "*return_addsi".  */
   else if (GET_CODE (src) == PLUS
           && arith_operand (XEXP (src, 0), SImode)
@@ -2273,6 +2453,117 @@ eligible_for_epilogue_delay (trial, slot)
               || register_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.  */
+  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;
+
+  /* sll{,x} reg,1,reg2 is add reg,reg,reg2 as well.  */
+  else if (GET_CODE (src) == ASHIFT
+          && (register_operand (XEXP (src, 0), SImode)
+              || register_operand (XEXP (src, 0), DImode))
+          && XEXP (src, 1) == const1_rtx)
+    return 1;
+
+  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 (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 (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;
 }
 
@@ -2326,10 +2617,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;
 }
 
@@ -2524,33 +2817,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 ();
@@ -2567,7 +2840,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
@@ -2576,16 +2849,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;
 
@@ -2643,11 +2908,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 (((current_function != 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
@@ -2695,6 +2962,9 @@ enum sparc_mode_class {
 /* Modes for quad-word and smaller quantities.  */
 #define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))
 
+/* Modes for 8-word and smaller quantities.  */
+#define O_MODES (T_MODES | (1 << (int) O_MODE) | (1 << (int) OF_MODE))
+
 /* Modes for single-float quantities.  We must allow any single word or
    smaller quantity.  This is because the fix/float conversion instructions
    take integer inputs/outputs from the float registers.  */
@@ -2703,13 +2973,8 @@ enum sparc_mode_class {
 /* Modes for double-float and smaller quantities.  */
 #define DF_MODES (S_MODES | D_MODES)
 
-#define DF_MODES64 DF_MODES
-
 /* Modes for double-float only quantities.  */
-#define DF_ONLY_MODES ((1 << (int) DF_MODE) | (1 << (int) D_MODE))
-
-/* Modes for double-float and larger quantities.  */
-#define DF_UP_MODES (DF_ONLY_MODES | TF_ONLY_MODES)
+#define DF_MODES_NO_S (D_MODES)
 
 /* Modes for quad-float only quantities.  */
 #define TF_ONLY_MODES (1 << (int) TF_MODE)
@@ -2717,7 +2982,16 @@ enum sparc_mode_class {
 /* Modes for quad-float and smaller quantities.  */
 #define TF_MODES (DF_MODES | TF_ONLY_MODES)
 
-#define TF_MODES64 (DF_MODES64 | TF_ONLY_MODES)
+/* Modes for quad-float and double-float quantities.  */
+#define TF_MODES_NO_S (DF_MODES_NO_S | TF_ONLY_MODES)
+
+/* Modes for quad-float pair only quantities.  */
+#define OF_ONLY_MODES (1 << (int) OF_MODE)
+
+/* Modes for quad-float pairs and smaller quantities.  */
+#define OF_MODES (TF_MODES | OF_ONLY_MODES)
+
+#define OF_MODES_NO_S (TF_MODES_NO_S | OF_ONLY_MODES)
 
 /* Modes for condition codes.  */
 #define CC_MODES (1 << (int) CC_MODE)
@@ -2738,17 +3012,17 @@ static int hard_32bit_mode_classes[] = {
   T_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
   T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
 
-  TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
-  TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
-  TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
-  TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
 
   /* FP regs f32 to f63.  Only the even numbered registers actually exist,
      and none can hold SFmode/SImode values.  */
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, TF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
 
   /* %fcc[0123] */
   CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
@@ -2759,21 +3033,21 @@ static int hard_32bit_mode_classes[] = {
 
 static int hard_64bit_mode_classes[] = {
   D_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
+  O_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
   T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
-  T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
-  T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
+  O_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
 
-  TF_MODES64, SF_MODES, DF_MODES64, SF_MODES, TF_MODES64, SF_MODES, DF_MODES64, SF_MODES,
-  TF_MODES64, SF_MODES, DF_MODES64, SF_MODES, TF_MODES64, SF_MODES, DF_MODES64, SF_MODES,
-  TF_MODES64, SF_MODES, DF_MODES64, SF_MODES, TF_MODES64, SF_MODES, DF_MODES64, SF_MODES,
-  TF_MODES64, SF_MODES, DF_MODES64, SF_MODES, TF_MODES64, SF_MODES, DF_MODES64, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
+  OF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
 
   /* FP regs f32 to f63.  Only the even numbered registers actually exist,
      and none can hold SFmode/SImode values.  */
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
-  DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
+  OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, TF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
 
   /* %fcc[0123] */
   CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
@@ -2967,11 +3241,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;
        }
@@ -2979,12 +3253,6 @@ restore_regs (file, low, high, base, offset, n_regs)
   return n_regs;
 }
 
-/* Static variables we want to share between prologue and epilogue.  */
-
-/* Number of live general or floating point registers needed to be saved
-   (as 4-byte quantities).  This is only done if TARGET_EPILOGUE.  */
-static int num_gfregs;
-
 /* Compute the frame size required by the function.  This function is called
    during the reload pass and also by output_function_prologue().  */
 
@@ -3083,7 +3351,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;
@@ -3136,7 +3404,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);
@@ -3151,26 +3419,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)
@@ -3259,6 +3507,40 @@ 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);
+}
+
 /* Output code for the function epilogue.  */
 
 void
@@ -3283,7 +3565,7 @@ output_function_epilogue (file, size, leaf_function)
 #endif
 
   else if (current_function_epilogue_delay_list == 0)
-    {                                                
+    {
       /* If code does not drop into the epilogue, we need
         do nothing except output pending case vectors.  */
       rtx insn = get_last_insn ();                               
@@ -3293,35 +3575,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)
@@ -3339,13 +3594,38 @@ output_function_epilogue (file, size, leaf_function)
          /* If we wound up with things in our delay slot, flush them here.  */
          if (current_function_epilogue_delay_list)
            {
-             rtx insn = emit_jump_insn_after (gen_rtx_RETURN (VOIDmode),
-                                              get_last_insn ());
-             PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode,
-                                       gen_rtvec (2,
-                                                  PATTERN (XEXP (current_function_epilogue_delay_list, 0)),
-                                                  PATTERN (insn)));
-             final_scan_insn (insn, file, 1, 0, 1);
+             rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0));
+
+             if (TARGET_V9 && ! epilogue_renumber (&delay, 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);
+               }
+             else
+               {
+                 rtx insn = emit_jump_insn_after (gen_rtx_RETURN (VOIDmode),
+                                                  get_last_insn ());
+                 rtx 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));
+                   }
+
+                 PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode,
+                                       gen_rtvec (2, delay, PATTERN (insn)));
+                 final_scan_insn (insn, file, 1, 0, 1);
+               }
            }
          else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P)
            fputs ("\treturn\t%i7+8\n\tnop\n", file);
@@ -3386,6 +3666,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.
 
@@ -3512,6 +3935,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;
@@ -3618,22 +4042,25 @@ 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
-       PROTO((int, struct function_arg_record_value_parms *));
+       PARAMS ((HOST_WIDE_INT, struct function_arg_record_value_parms *));
 static void function_arg_record_value_2
-       PROTO((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
-        PROTO((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
-       PROTO((tree, enum machine_mode, int, int, int));
+       PARAMS ((tree, enum machine_mode, int, int, int));
 
 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;
@@ -3661,15 +4088,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
@@ -3707,15 +4135,17 @@ function_arg_record_value_1 (type, startbitpos, parms)
 
 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;
+  int this_slotno, intslots, intoffset;
   rtx reg;
 
   if (parms->intoffset == -1)
     return;
+
   intoffset = parms->intoffset;
   parms->intoffset = -1;
 
@@ -3732,10 +4162,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;
 
@@ -3758,7 +4186,7 @@ function_arg_record_value_3 (bitpos, parms)
 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;
@@ -3777,15 +4205,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
@@ -3822,7 +4251,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;
@@ -4329,7 +4758,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))
@@ -4352,12 +4781,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;
@@ -4384,6 +4807,37 @@ 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);
+      MEM_ALIAS_SET (addr_rtx) = get_varargs_alias_set ();
+      tmp = shallow_copy_rtx (tmp);
+      PUT_MODE (tmp, BLKmode);
+      MEM_ALIAS_SET (tmp) = 0;
+      
+      dest_addr = emit_block_move (tmp, addr_rtx, GEN_INT (rsize), 
+                                  BITS_PER_WORD);
+      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);
@@ -4423,158 +4877,128 @@ output_cbranch (op, label, reversed, annul, noop, insn)
   static char v9_xcc_labelno[] = "%%xcc, %lX";
   static char v9_fcc_labelno[] = "%%fccX, %lY";
   char *labelno;
+  const char *branch;
   int labeloff, spaces = 8;
 
-  /* ??? !v9: FP branches cannot be preceded by another floating point insn.
-     Because there is currently no concept of pre-delay slots, we can fix
-     this only by always emitting a nop before a floating point branch.  */
-
-  if ((mode == CCFPmode || mode == CCFPEmode) && ! TARGET_V9)
-    strcpy (string, "nop\n\t");
-  else
-    string[0] = '\0';
-
-  /* If not floating-point or if EQ or NE, we can just reverse the code.  */
-  if (reversed
-      && ((mode != CCFPmode && mode != CCFPEmode) || code == EQ || code == NE))
-    code = reverse_condition (code), reversed = 0;
-
-  /* Start by writing the branch condition.  */
-  switch (code)
+  if (reversed)
     {
-    case NE:
+      /* Reversal of FP compares takes care -- an ordered compare
+        becomes an unordered compare and vice versa.  */
       if (mode == CCFPmode || mode == CCFPEmode)
-       {
-         strcat (string, "fbne");
-         spaces -= 4;
-       }
+       code = reverse_condition_maybe_unordered (code);
       else
-       {
-         strcpy (string, "bne");
-         spaces -= 3;
-       }
-      break;
+       code = reverse_condition (code);
+    }
 
-    case EQ:
-      if (mode == CCFPmode || mode == CCFPEmode)
-       {
-         strcat (string, "fbe");
-         spaces -= 3;
-       }
-      else
+  /* Start by writing the branch condition.  */
+  if (mode == CCFPmode || mode == CCFPEmode)
+    {
+      switch (code)
        {
-         strcpy (string, "be");
-         spaces -= 2;
-       }
-      break;
+       case NE:
+         branch = "fbne";
+         break;
+       case EQ:
+         branch = "fbe";
+         break;
+       case GE:
+         branch = "fbge";
+         break;
+       case GT:
+         branch = "fbg";
+         break;
+       case LE:
+         branch = "fble";
+         break;
+       case LT:
+         branch = "fbl";
+         break;
+       case UNORDERED:
+         branch = "fbu";
+         break;
+       case ORDERED:
+         branch = "fbo";
+         break;
+       case UNGT:
+         branch = "fbug";
+         break;
+       case UNLT:
+         branch = "fbul";
+         break;
+       case UNEQ:
+         branch = "fbue";
+         break;
+       case UNGE:
+         branch = "fbuge";
+         break;
+       case UNLE:
+         branch = "fbule";
+         break;
+       case LTGT:
+         branch = "fblg";
+         break;
 
-    case GE:
-      if (mode == CCFPmode || mode == CCFPEmode)
-       {
-         if (reversed)
-           strcat (string, "fbul");
-         else
-           strcat (string, "fbge");
-         spaces -= 4;
-       }
-      else if (mode == CC_NOOVmode)
-       {
-         strcpy (string, "bpos");
-         spaces -= 4;
-       }
-      else
-       {
-         strcpy (string, "bge");
-         spaces -= 3;
+       default:
+         abort ();
        }
-      break;
 
-    case GT:
-      if (mode == CCFPmode || mode == CCFPEmode)
-       {
-         if (reversed)
-           {
-             strcat (string, "fbule");
-             spaces -= 5;
-           }
-         else
-           {
-             strcat (string, "fbg");
-             spaces -= 3;
-           }
-       }
-      else
-       {
-         strcpy (string, "bg");
-         spaces -= 2;
-       }
-      break;
+      /* ??? !v9: FP branches cannot be preceded by another floating point
+        insn.  Because there is currently no concept of pre-delay slots,
+        we can fix this only by always emitting a nop before a floating
+        point branch.  */
 
-    case LE:
-      if (mode == CCFPmode || mode == CCFPEmode)
+      string[0] = '\0';
+      if (! TARGET_V9)
+       strcpy (string, "nop\n\t");
+      strcat (string, branch);
+    }
+  else
+    {
+      switch (code)
        {
-         if (reversed)
-           strcat (string, "fbug");
+       case NE:
+         branch = "bne";
+         break;
+       case EQ:
+         branch = "be";
+         break;
+       case GE:
+         if (mode == CC_NOOVmode)
+           branch = "bpos";
          else
-           strcat (string, "fble");
-         spaces -= 4;
-       }
-      else
-       {
-         strcpy (string, "ble");
-         spaces -= 3;
-       }
-      break;
-
-    case LT:
-      if (mode == CCFPmode || mode == CCFPEmode)
-       {
-         if (reversed)
-           {
-             strcat (string, "fbuge");
-             spaces -= 5;
-           }
+           branch = "bge";
+         break;
+       case GT:
+         branch = "bg";
+         break;
+       case LE:
+         branch = "ble";
+         break;
+       case LT:
+         if (mode == CC_NOOVmode)
+           branch = "bneg";
          else
-           {
-             strcat (string, "fbl");
-             spaces -= 3;
-           }
-       }
-      else if (mode == CC_NOOVmode)
-       {
-         strcpy (string, "bneg");
-         spaces -= 4;
-       }
-      else
-       {
-         strcpy (string, "bl");
-         spaces -= 2;
-       }
-      break;
-
-    case GEU:
-      strcpy (string, "bgeu");
-      spaces -= 4;
-      break;
-
-    case GTU:
-      strcpy (string, "bgu");
-      spaces -= 3;
-      break;
-
-    case LEU:
-      strcpy (string, "bleu");
-      spaces -= 4;
-      break;
-
-    case LTU:
-      strcpy (string, "blu");
-      spaces -= 3;
-      break;
+           branch = "bl";
+         break;
+       case GEU:
+         branch = "bgeu";
+         break;
+       case GTU:
+         branch = "bgu";
+         break;
+       case LEU:
+         branch = "bleu";
+         break;
+       case LTU:
+         branch = "blu";
+         break;
 
-    default:
-      abort ();
+       default:
+         abort ();
+       }
+      strcpy (string, branch);
     }
+  spaces -= strlen (branch);
 
   /* Now add the annulling, the label, and a possible noop.  */
   if (annul)
@@ -4627,6 +5051,153 @@ output_cbranch (op, label, reversed, annul, noop, insn)
   return string;
 }
 
+/* Emit a library call comparison between floating point X and Y.
+   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).
+   TARGET_ARCH64 uses _Qp_* functions, which use pointers to TFmode
+   values as arguments instead of the TFmode registers themselves,
+   that's why we cannot call emit_float_lib_cmp.  */
+void
+sparc_emit_float_lib_cmp (x, y, comparison)
+     rtx x, y;
+     enum rtx_code comparison;
+{
+  const char *qpfunc;
+  rtx slot0, slot1, result, tem, tem2;
+  enum machine_mode mode;
+
+  switch (comparison)
+    {
+    case EQ:
+      qpfunc = (TARGET_ARCH64) ? "_Qp_feq" : "_Q_feq";
+      break;
+
+    case NE:
+      qpfunc = (TARGET_ARCH64) ? "_Qp_fne" : "_Q_fne";
+      break;
+
+    case GT:
+      qpfunc = (TARGET_ARCH64) ? "_Qp_fgt" : "_Q_fgt";
+      break;
+
+    case GE:
+      qpfunc = (TARGET_ARCH64) ? "_Qp_fge" : "_Q_fge";
+      break;
+
+    case LT:
+      qpfunc = (TARGET_ARCH64) ? "_Qp_flt" : "_Q_flt";
+      break;
+
+    case LE:
+      qpfunc = (TARGET_ARCH64) ? "_Qp_fle" : "_Q_fle";
+      break;
+
+    case ORDERED:
+    case UNORDERED:
+    case UNGT:
+    case UNLT:
+    case UNEQ:
+    case UNGE:
+    case UNLE:
+    case LTGT:
+      qpfunc = (TARGET_ARCH64) ? "_Qp_cmp" : "_Q_cmp";
+      break;
+
+    default:
+      abort();
+      break;
+    }
+
+  if (TARGET_ARCH64)
+    {
+      if (GET_CODE (x) != MEM)
+       {
+         slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot0, x));
+       }
+      else
+       slot0 = x;
+
+      if (GET_CODE (y) != MEM)
+       {
+         slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
+         emit_insn (gen_rtx_SET (VOIDmode, slot1, y));
+       }
+      else
+       slot1 = y;
+
+      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), 1,
+                        DImode, 2,
+                        XEXP (slot0, 0), Pmode,
+                        XEXP (slot1, 0), Pmode);
+
+      mode = DImode;
+    }
+  else
+    {
+      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), 1,
+                        SImode, 2,
+                        x, TFmode, y, TFmode);
+
+      mode = SImode;
+    }
+
+
+  /* Immediately move the result of the libcall into a pseudo
+     register so reload doesn't clobber the value if it needs
+     the return register for a spill reg.  */
+  result = gen_reg_rtx (mode);
+  emit_move_insn (result, hard_libcall_value (mode));
+
+  switch (comparison)
+    {
+    default:
+      emit_cmp_insn (result, const0_rtx, NE,
+                    NULL_RTX, mode, 0, 0);
+      break;
+    case ORDERED:
+    case UNORDERED:
+      emit_cmp_insn (result, GEN_INT(3),
+                    (comparison == UNORDERED) ? EQ : NE,
+                    NULL_RTX, mode, 0, 0);
+      break;
+    case UNGT:
+    case UNGE:
+      emit_cmp_insn (result, const1_rtx,
+                    (comparison == UNGT) ? GT : NE,
+                    NULL_RTX, mode, 0, 0);
+      break;
+    case UNLE:
+      emit_cmp_insn (result, const2_rtx, NE,
+                    NULL_RTX, mode, 0, 0);
+      break;
+    case UNLT:
+      tem = gen_reg_rtx (mode);
+      if (TARGET_ARCH32)
+       emit_insn (gen_andsi3 (tem, result, const1_rtx));
+      else
+       emit_insn (gen_anddi3 (tem, result, const1_rtx));
+      emit_cmp_insn (tem, const0_rtx, NE,
+                    NULL_RTX, mode, 0, 0);
+      break;
+    case UNEQ:
+    case LTGT:
+      tem = gen_reg_rtx (mode);
+      if (TARGET_ARCH32)
+       emit_insn (gen_addsi3 (tem, result, const1_rtx));
+      else
+       emit_insn (gen_adddi3 (tem, result, const1_rtx));
+      tem2 = gen_reg_rtx (mode);
+      if (TARGET_ARCH32)
+       emit_insn (gen_andsi3 (tem2, tem, const2_rtx));
+      else
+       emit_insn (gen_anddi3 (tem2, tem, const2_rtx));
+      emit_cmp_insn (tem2, const0_rtx,
+                    (comparison == UNEQ) ? EQ : NE,
+                    NULL_RTX, mode, 0, 0);
+      break;
+    }
+}
+
 /* Return the string to output a conditional branch to LABEL, testing
    register REG.  LABEL is the operand number of the label; REG is the
    operand number of the reg.  OP is the conditional expression.  The mode
@@ -4726,56 +5297,59 @@ output_v9branch (op, reg, label, reversed, annul, noop, insn)
   return string;
 }
 
-/* Renumber registers in delay slot.  Replace registers instead of
-   renumbering because they may be shared.
-
  This does not handle instructions other than move.  */
+/* Return 1, if any of the registers of the instruction are %l[0-7] or %o[0-7].
+   Such instructions cannot be used in the delay slot of return insn on v9.
+   If TEST is 0, also rename all %i[0-7] registers to their %o[0-7] counterparts.
+ */
 
-static void
-epilogue_renumber (where)
-     rtx *where;
+static int
+epilogue_renumber (where, test)
+     register rtx *where;
+     int test;
 {
-  rtx x = *where;
-  enum rtx_code code = GET_CODE (x);
+  register const char *fmt;
+  register int i;
+  register enum rtx_code code;
+
+  if (*where == 0)
+    return 0;
+
+  code = GET_CODE (*where);
 
   switch (code)
     {
-    case MEM:
-      *where = x = copy_rtx (x);
-      epilogue_renumber (&XEXP (x, 0));
-      return;
-
     case REG:
-      {
-       int regno = REGNO (x);
-       if (regno > 8 && regno < 24)
-         abort ();
-       if (regno >= 24 && regno < 32)
-         *where = gen_rtx_REG (GET_MODE (x), regno - 16);
-       return;
-      }
+      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)));
+    case SCRATCH:
+    case CC0:
+    case PC:
     case CONST_INT:
     case CONST_DOUBLE:
-    case CONST:
-    case SYMBOL_REF:
-    case LABEL_REF:
-      return;
-
-    case IOR:
-    case AND:
-    case XOR:
-    case PLUS:
-    case MINUS:
-      epilogue_renumber (&XEXP (x, 1));
-    case NEG:
-    case NOT:
-      epilogue_renumber (&XEXP (x, 0));
-      return;
+      return 0;
 
     default:
-      debug_rtx (*where);
-      abort ();
+      break;
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         register int j;
+         for (j = XVECLEN (*where, i) - 1; j >= 0; j--)
+           if (epilogue_renumber (&(XVECEXP (*where, i, j)), test))
+             return 1;
+       }
+      else if (fmt[i] == 'e'
+              && epilogue_renumber (&(XEXP (*where, i)), test))
+       return 1;
     }
+  return 0;
 }
 
 /* Output assembler code to return from a function.  */
@@ -4831,17 +5405,17 @@ 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)
     {
       if (delay)
        {
-         epilogue_renumber (&SET_DEST (PATTERN (delay)));
-         epilogue_renumber (&SET_SRC (PATTERN (delay)));
+         epilogue_renumber (&SET_DEST (PATTERN (delay)), 0);
+         epilogue_renumber (&SET_SRC (PATTERN (delay)), 0);
        }
       if (SKIP_CALLERS_UNIMP_P)
        return "return\t%%i7+12%#";
@@ -4879,8 +5453,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,
+             (char *) reg_alloc_orders[last_order_nonleaf],
+             FIRST_PSEUDO_REGISTER * sizeof (int));
     }
 }
 \f
@@ -5190,9 +5765,16 @@ print_operand (file, x, code)
     case 'c' :
     case 'C':
       {
-       enum rtx_code rc = (code == 'c'
-                           ? reverse_condition (GET_CODE (x))
-                           : GET_CODE (x));
+       enum rtx_code rc = GET_CODE (x);
+       
+       if (code == 'c')
+         {
+           enum machine_mode mode = GET_MODE (XEXP (x, 0));
+           if (mode == CCFPmode || mode == CCFPEmode)
+             rc = reverse_condition_maybe_unordered (GET_CODE (x));
+           else
+             rc = reverse_condition (GET_CODE (x));
+         }
        switch (rc)
          {
          case NE: fputs ("ne", file); break;
@@ -5205,6 +5787,14 @@ print_operand (file, x, code)
          case GTU: fputs ("gu", file); break;
          case LEU: fputs ("leu", file); break;
          case LTU: fputs ("lu", file); break;
+         case LTGT: fputs ("lg", file); break;
+         case UNORDERED: fputs ("u", file); break;
+         case ORDERED: fputs ("o", file); break;
+         case UNLT: fputs ("ul", file); break;
+         case UNLE: fputs ("ule", file); break;
+         case UNGT: fputs ("ug", file); break;
+         case UNGE: fputs ("uge", file); break;
+         case UNEQ: fputs ("ue", file); break;
          default: output_operand_lossage (code == 'c'
                                           ? "Invalid %%c operand"
                                           : "Invalid %%C operand");
@@ -5266,8 +5856,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);
@@ -5293,10 +5882,10 @@ print_operand (file, x, code)
               || GET_MODE_CLASS (GET_MODE (x)) == MODE_INT))
     {
       if (CONST_DOUBLE_HIGH (x) == 0)
-       fprintf (file, "%u", CONST_DOUBLE_LOW (x));
+       fprintf (file, "%u", (unsigned int) CONST_DOUBLE_LOW (x));
       else if (CONST_DOUBLE_HIGH (x) == -1
               && CONST_DOUBLE_LOW (x) < 0)
-       fprintf (file, "%d", CONST_DOUBLE_LOW (x));
+       fprintf (file, "%d", (int) CONST_DOUBLE_LOW (x));
       else
        output_operand_lossage ("long long constant not a valid immediate operand");
     }
@@ -5611,10 +6200,10 @@ sparc64_initialize_trampoline (tramp, fnaddr, cxt)
                  GEN_INT (0xca586010));
   emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 16)), cxt);
   emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 24)), fnaddr);
-  emit_insn (gen_flush (validize_mem (gen_rtx_MEM (DImode, tramp))));
+  emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, tramp))));
 
   if (sparc_cpu != PROCESSOR_ULTRASPARC)
-    emit_insn (gen_flush (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8)))));
+    emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8)))));
 }
 \f
 /* Subroutines to support a flat (single) register window calling
@@ -5997,7 +6586,7 @@ 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)
            {
@@ -6182,7 +6771,7 @@ sparc_flat_output_function_epilogue (file, size)
        }
 
       /* 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;
        }
@@ -6294,12 +6883,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;
@@ -6650,8 +7233,8 @@ enum ultra_code { NONE=0, /* no insn at all                               */
                  SINGLE, /* single issue instructions                  */
                  NUM_ULTRA_CODES };
 
-static enum ultra_code ultra_code_from_mask PROTO ((int));
-static void ultra_schedule_insn PROTO ((rtx *, rtx *, int, enum ultra_code));
+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] = {
   "NONE", "IEU0", "IEU1", "IEUN", "LSU", "CTI",
@@ -6697,6 +7280,7 @@ 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) |
@@ -6731,7 +7315,7 @@ ultra_cmove_results_ready_p (insn)
 
   /* If this got dispatched in the previous
      group, the results are not ready.  */
-  entry = (ultra_cur_hist - 1) % (ULTRA_NUM_HIST - 1);
+  entry = (ultra_cur_hist - 1) & (ULTRA_NUM_HIST - 1);
   up = &ultra_pipe_hist[entry];
   slot = 4;
   while (--slot >= 0)
@@ -6752,7 +7336,7 @@ ultra_fpmode_conflict_exists (fpmode)
   int hist_ent;
   int hist_lim;
 
-  hist_ent = (ultra_cur_hist - 1) % (ULTRA_NUM_HIST - 1);
+  hist_ent = (ultra_cur_hist - 1) & (ULTRA_NUM_HIST - 1);
   if (ultra_cycles_elapsed < 4)
     hist_lim = ultra_cycles_elapsed;
   else
@@ -6793,7 +7377,7 @@ ultra_fpmode_conflict_exists (fpmode)
            return 1;
        }
       hist_lim--;
-      hist_ent = (hist_ent - 1) % (ULTRA_NUM_HIST - 1);
+      hist_ent = (hist_ent - 1) & (ULTRA_NUM_HIST - 1);
     }
 
   /* No conflicts, safe to dispatch.  */
@@ -6981,9 +7565,9 @@ ultra_schedule_insn (ip, ready, this, type)
 static void
 ultra_flush_pipeline ()
 {
-  ultra_cur_hist = (ultra_cur_hist + 1) % (ULTRA_NUM_HIST - 1);
+  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;
 }
 
@@ -6993,7 +7577,7 @@ ultrasparc_sched_init (dump, sched_verbose)
      FILE *dump ATTRIBUTE_UNUSED;
      int sched_verbose ATTRIBUTE_UNUSED;
 {
-  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;
@@ -7169,6 +7753,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);
@@ -7328,7 +7913,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;
       }
   }
@@ -7381,8 +7966,8 @@ sparc_issue_rate ()
 }
 
 static int
-set_extends(x, insn)
-     rtx x, insn;
+set_extends (insn)
+     rtx insn;
 {
   register rtx pat = PATTERN (insn);
 
@@ -7406,27 +7991,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;
     }
@@ -7548,10 +8146,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)
@@ -7581,8 +8185,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;
          }
        }
@@ -7602,21 +8208,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");
 }
 
 
@@ -7653,22 +8259,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);
 }
 
 
@@ -7740,17 +8346,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)
     {
@@ -7759,11 +8365,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);
 
@@ -7780,9 +8386,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);
 
@@ -7861,32 +8467,33 @@ sparc_block_profiler(file, blockno)
      int blockno;
 {
   char LPBX[32];
+  int bbreg = TARGET_ARCH64 ? 4 : 2;
 
   if (profile_block_flag == 2)
     {
       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),%%g2\n", blockno);
-      fprintf (file, "\tor\t%%g1,%%lo(%s__bb),%%g1\n", user_label_prefix);
-      fprintf (file, "\tor\t%%g2,%%lo(%d),%%g2\n", blockno);
+      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);
 
-      fputs ("\tst\t%g2,[%g1]\n", file);
+      fprintf (file, "\tst\t%%g%d, [%%g1]\n", bbreg);
 
       fputs ("\tsethi\t%hi(", file);
       assemble_name (file, LPBX);
-      fputs ("),%g2\n", file);
+      fprintf (file, "), %%g%d\n", bbreg);
   
-      fputs ("\tor\t%o2,%lo(", file);
+      fputs ("\tor\t%o2, %lo(", file);
       assemble_name (file, LPBX);
-      fputs ("),%g2\n", file);
+      fprintf (file, "), %%g%d\n", bbreg);
   
-      fputs ("\tst\t%g2,[%g1+4]\n", file);
-      fputs ("\tmov\t%o7,%g2\n", file);
+      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);
 
-      fputs ("\tmov\t%g2,%o7\n", file);
+      fprintf (file, "\tmov\t%%g%d, %%o7\n", bbreg);
     }
   else if (profile_block_flag != 0)
     {
@@ -7894,17 +8501,23 @@ 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);
-      fprintf (file, "+%d)],%%g2\n", blockno*4);
+      if (TARGET_ARCH64 && USE_AS_OFFSETABLE_LO10)
+       fprintf (file, ")+%d], %%g%d\n", blockno*4, bbreg);
+      else
+       fprintf (file, "+%d)], %%g%d\n", blockno*4, bbreg);
 
-      fputs ("\tadd\t%g2,1,%g2\n", file);
+      fprintf (file, "\tadd\t%%g%d, 1, %%g%d\n", bbreg, bbreg);
 
-      fputs ("\tst\t%g2,[%g1+%lo(", file);
+      fprintf (file, "\tst\t%%g%d, [%%g1+%%lo(", bbreg);
       assemble_name (file, LPBX);
-      fprintf (file, "+%d)]\n", blockno*4);
+      if (TARGET_ARCH64 && USE_AS_OFFSETABLE_LO10)
+       fprintf (file, ")+%d]\n", blockno*4);
+      else
+       fprintf (file, "+%d)]\n", blockno*4);
     }
 }
 
@@ -7968,8 +8581,6 @@ 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);
 }