OSDN Git Service

* final.c (output_in_slot): New global variable.
[pf3gnuchains/gcc-fork.git] / gcc / config / sparc / sparc.c
index 01530cf..cf7ac04 100644 (file)
@@ -49,15 +49,162 @@ Boston, MA 02111-1307, USA.  */
 #include "cfglayout.h"
 #include "tree-gimple.h"
 
+/* Processor costs */
+static const
+struct processor_costs cypress_costs = {
+  COSTS_N_INSNS (2), /* int load */
+  COSTS_N_INSNS (2), /* int signed load */
+  COSTS_N_INSNS (2), /* int zeroed load */
+  COSTS_N_INSNS (2), /* float load */
+  COSTS_N_INSNS (5), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (5), /* fadd, fsub */
+  COSTS_N_INSNS (1), /* fcmp */
+  COSTS_N_INSNS (1), /* fmov, fmovr */
+  COSTS_N_INSNS (7), /* fmul */
+  COSTS_N_INSNS (37), /* fdivs */
+  COSTS_N_INSNS (37), /* fdivd */
+  COSTS_N_INSNS (63), /* fsqrts */
+  COSTS_N_INSNS (63), /* fsqrtd */
+  COSTS_N_INSNS (1), /* imul */
+  COSTS_N_INSNS (1), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (1), /* idiv */
+  COSTS_N_INSNS (1), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+};
+
+static const
+struct processor_costs supersparc_costs = {
+  COSTS_N_INSNS (1), /* int load */
+  COSTS_N_INSNS (1), /* int signed load */
+  COSTS_N_INSNS (1), /* int zeroed load */
+  COSTS_N_INSNS (0), /* float load */
+  COSTS_N_INSNS (3), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (3), /* fadd, fsub */
+  COSTS_N_INSNS (3), /* fcmp */
+  COSTS_N_INSNS (1), /* fmov, fmovr */
+  COSTS_N_INSNS (3), /* fmul */
+  COSTS_N_INSNS (6), /* fdivs */
+  COSTS_N_INSNS (9), /* fdivd */
+  COSTS_N_INSNS (12), /* fsqrts */
+  COSTS_N_INSNS (12), /* fsqrtd */
+  COSTS_N_INSNS (4), /* imul */
+  COSTS_N_INSNS (4), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (4), /* idiv */
+  COSTS_N_INSNS (4), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  1, /* shift penalty */
+};
+
+static const
+struct processor_costs hypersparc_costs = {
+  COSTS_N_INSNS (1), /* int load */
+  COSTS_N_INSNS (1), /* int signed load */
+  COSTS_N_INSNS (1), /* int zeroed load */
+  COSTS_N_INSNS (1), /* float load */
+  COSTS_N_INSNS (1), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (1), /* fadd, fsub */
+  COSTS_N_INSNS (1), /* fcmp */
+  COSTS_N_INSNS (1), /* fmov, fmovr */
+  COSTS_N_INSNS (1), /* fmul */
+  COSTS_N_INSNS (8), /* fdivs */
+  COSTS_N_INSNS (12), /* fdivd */
+  COSTS_N_INSNS (17), /* fsqrts */
+  COSTS_N_INSNS (17), /* fsqrtd */
+  COSTS_N_INSNS (17), /* imul */
+  COSTS_N_INSNS (17), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (17), /* idiv */
+  COSTS_N_INSNS (17), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+};
+
+static const
+struct processor_costs sparclet_costs = {
+  COSTS_N_INSNS (3), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (1), /* int zeroed load */
+  COSTS_N_INSNS (1), /* float load */
+  COSTS_N_INSNS (1), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (1), /* fadd, fsub */
+  COSTS_N_INSNS (1), /* fcmp */
+  COSTS_N_INSNS (1), /* fmov, fmovr */
+  COSTS_N_INSNS (1), /* fmul */
+  COSTS_N_INSNS (1), /* fdivs */
+  COSTS_N_INSNS (1), /* fdivd */
+  COSTS_N_INSNS (1), /* fsqrts */
+  COSTS_N_INSNS (1), /* fsqrtd */
+  COSTS_N_INSNS (5), /* imul */
+  COSTS_N_INSNS (5), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (5), /* idiv */
+  COSTS_N_INSNS (5), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+};
+
+static const
+struct processor_costs ultrasparc_costs = {
+  COSTS_N_INSNS (2), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (2), /* int zeroed load */
+  COSTS_N_INSNS (2), /* float load */
+  COSTS_N_INSNS (1), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (4), /* fadd, fsub */
+  COSTS_N_INSNS (1), /* fcmp */
+  COSTS_N_INSNS (2), /* fmov, fmovr */
+  COSTS_N_INSNS (4), /* fmul */
+  COSTS_N_INSNS (13), /* fdivs */
+  COSTS_N_INSNS (23), /* fdivd */
+  COSTS_N_INSNS (13), /* fsqrts */
+  COSTS_N_INSNS (23), /* fsqrtd */
+  COSTS_N_INSNS (4), /* imul */
+  COSTS_N_INSNS (4), /* imulX */
+  2, /* imul bit factor */
+  COSTS_N_INSNS (37), /* idiv */
+  COSTS_N_INSNS (68), /* idivX */
+  COSTS_N_INSNS (2), /* movcc/movr */
+  2, /* shift penalty */
+};
+
+static const
+struct processor_costs ultrasparc3_costs = {
+  COSTS_N_INSNS (2), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (3), /* int zeroed load */
+  COSTS_N_INSNS (2), /* float load */
+  COSTS_N_INSNS (3), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (4), /* fadd, fsub */
+  COSTS_N_INSNS (5), /* fcmp */
+  COSTS_N_INSNS (3), /* fmov, fmovr */
+  COSTS_N_INSNS (4), /* fmul */
+  COSTS_N_INSNS (17), /* fdivs */
+  COSTS_N_INSNS (20), /* fdivd */
+  COSTS_N_INSNS (20), /* fsqrts */
+  COSTS_N_INSNS (29), /* fsqrtd */
+  COSTS_N_INSNS (6), /* imul */
+  COSTS_N_INSNS (6), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (40), /* idiv */
+  COSTS_N_INSNS (71), /* idivX */
+  COSTS_N_INSNS (2), /* movcc/movr */
+  0, /* shift penalty */
+};
+
+const struct processor_costs *sparc_costs = &cypress_costs;
+
 #ifdef HAVE_AS_RELAX_OPTION
 /* If 'as' and 'ld' are relaxing tail call insns into branch always, use
    "or %o7,%g0,X; call Y; or X,%g0,%o7" always, so that it can be optimized.
    With sethi/jmp, neither 'as' nor 'ld' has an easy way how to find out if
    somebody does not branch between the sethi and jmp.  */
-#define SIBCALL_SLOT_EMPTY_P 0
+#define LEAF_SIBCALL_SLOT_RESERVED_P 1
 #else
-#define SIBCALL_SLOT_EMPTY_P \
-  ((TARGET_ARCH32 || TARGET_CM_MEDLOW) && ! flag_pic)
+#define LEAF_SIBCALL_SLOT_RESERVED_P \
+  ((TARGET_ARCH64 && !TARGET_CM_MEDLOW) || flag_pic)
 #endif
 
 /* Global variables for machine-dependent things.  */
@@ -161,7 +308,6 @@ static void sparc_elf_asm_named_section (const char *, unsigned int);
 static int sparc_adjust_cost (rtx, rtx, rtx, int);
 static int sparc_issue_rate (void);
 static void sparc_sched_init (FILE *, int, int);
-static int sparc_use_dfa_pipeline_interface (void);
 static int sparc_use_sched_lookahead (void);
 
 static void emit_soft_tfmode_libcall (const char *, int, rtx *);
@@ -186,6 +332,11 @@ static rtx sparc_struct_value_rtx (tree, int);
 static bool sparc_return_in_memory (tree, tree);
 static bool sparc_strict_argument_naming (CUMULATIVE_ARGS *);
 static tree sparc_gimplify_va_arg (tree, tree, tree *, tree *);
+static bool sparc_pass_by_reference (CUMULATIVE_ARGS *,
+                                    enum machine_mode, tree, bool);
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+const struct attribute_spec sparc_attribute_table[];
+#endif
 \f
 /* Option handling.  */
 
@@ -241,8 +392,6 @@ enum processor_type sparc_cpu;
 #define TARGET_SCHED_ISSUE_RATE sparc_issue_rate
 #undef TARGET_SCHED_INIT
 #define TARGET_SCHED_INIT sparc_sched_init
-#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
-#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE sparc_use_dfa_pipeline_interface
 #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD sparc_use_sched_lookahead
 
@@ -288,6 +437,10 @@ enum processor_type sparc_cpu;
 #define TARGET_STRUCT_VALUE_RTX sparc_struct_value_rtx
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY sparc_return_in_memory
+#undef TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE sparc_pass_by_reference
 
 #undef TARGET_EXPAND_BUILTIN_SAVEREGS
 #define TARGET_EXPAND_BUILTIN_SAVEREGS sparc_builtin_saveregs
@@ -300,6 +453,16 @@ enum processor_type sparc_cpu;
 #undef TARGET_LATE_RTL_PROLOGUE_EPILOGUE
 #define TARGET_LATE_RTL_PROLOGUE_EPILOGUE true
 
+#ifdef SUBTARGET_INSERT_ATTRIBUTES
+#undef TARGET_INSERT_ATTRIBUTES
+#define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
+#endif
+
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE sparc_attribute_table
+#endif
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Validate and override various options, and do some machine dependent
@@ -504,8 +667,48 @@ sparc_override_options (void)
 
   /* Set up function hooks.  */
   init_machine_status = sparc_init_machine_status;
+
+  switch (sparc_cpu)
+    {
+    case PROCESSOR_V7:
+    case PROCESSOR_CYPRESS:
+      sparc_costs = &cypress_costs;
+      break;
+    case PROCESSOR_V8:
+    case PROCESSOR_SPARCLITE:
+    case PROCESSOR_SUPERSPARC:
+      sparc_costs = &supersparc_costs;
+      break;
+    case PROCESSOR_F930:
+    case PROCESSOR_F934:
+    case PROCESSOR_HYPERSPARC:
+    case PROCESSOR_SPARCLITE86X:
+      sparc_costs = &hypersparc_costs;
+      break;
+    case PROCESSOR_SPARCLET:
+    case PROCESSOR_TSC701:
+      sparc_costs = &sparclet_costs;
+      break;
+    case PROCESSOR_V9:
+    case PROCESSOR_ULTRASPARC:
+      sparc_costs = &ultrasparc_costs;
+      break;
+    case PROCESSOR_ULTRASPARC3:
+      sparc_costs = &ultrasparc3_costs;
+      break;
+    };
 }
 \f
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+/* Table of valid machine attributes.  */
+const struct attribute_spec sparc_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  SUBTARGET_ATTRIBUTE_TABLE,
+  { NULL,        0, 0, false, false, false, NULL }
+};
+#endif
+\f
 /* Miscellaneous utilities.  */
 
 /* Nonzero if CODE, a comparison, is suitable for use in v9 conditional move
@@ -1438,18 +1641,25 @@ sparc_emit_set_const32 (rtx op0, rtx op1)
 }
 
 \f
-/* SPARC-v9 code-model support.  */
+/* Load OP1, a symbolic 64-bit constant, into OP0, a DImode register.
+   If TEMP is non-zero, we are forbidden to use any other scratch
+   registers.  Otherwise, we are allowed to generate them as needed.
+
+   Note that TEMP may have TImode if the code model is TARGET_CM_MEDANY
+   or TARGET_CM_EMBMEDANY (see the reload_indi and reload_outdi patterns).  */
 void
-sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp1)
+sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
 {
-  rtx ti_temp1 = 0;
+  rtx temp1, temp2, temp3, temp4, temp5;
+  rtx ti_temp = 0;
 
-  if (temp1 && GET_MODE (temp1) == TImode)
+  if (temp && GET_MODE (temp) == TImode)
     {
-      ti_temp1 = temp1;
-      temp1 = gen_rtx_REG (DImode, REGNO (temp1));
+      ti_temp = temp;
+      temp = gen_rtx_REG (DImode, REGNO (temp));
     }
 
+  /* SPARC-V9 code-model support.  */
   switch (sparc_cmodel)
     {
     case CM_MEDLOW:
@@ -1461,8 +1671,13 @@ sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp1)
         The executable must be in the low 4TB of the virtual address
         space.
 
-        sethi  %hi(symbol), %temp
-        or     %temp, %lo(symbol), %reg  */
+        sethi  %hi(symbol), %temp1
+        or     %temp1, %lo(symbol), %reg  */
+      if (temp)
+       temp1 = temp;  /* op0 is allowed.  */
+      else
+       temp1 = gen_reg_rtx (DImode);
+
       emit_insn (gen_rtx_SET (VOIDmode, temp1, gen_rtx_HIGH (DImode, op1)));
       emit_insn (gen_rtx_SET (VOIDmode, op0, gen_rtx_LO_SUM (DImode, temp1, op1)));
       break;
@@ -1480,11 +1695,24 @@ sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp1)
         or     %temp1, %m44(symbol), %temp2
         sllx   %temp2, 12, %temp3
         or     %temp3, %l44(symbol), %reg  */
-      emit_insn (gen_seth44 (op0, op1));
-      emit_insn (gen_setm44 (op0, op0, op1));
-      emit_insn (gen_rtx_SET (VOIDmode, temp1,
-                             gen_rtx_ASHIFT (DImode, op0, GEN_INT (12))));
-      emit_insn (gen_setl44 (op0, temp1, op1));
+      if (temp)
+       {
+         temp1 = op0;
+         temp2 = op0;
+         temp3 = temp;  /* op0 is allowed.  */
+       }
+      else
+       {
+         temp1 = gen_reg_rtx (DImode);
+         temp2 = gen_reg_rtx (DImode);
+         temp3 = gen_reg_rtx (DImode);
+       }
+
+      emit_insn (gen_seth44 (temp1, op1));
+      emit_insn (gen_setm44 (temp2, temp1, op1));
+      emit_insn (gen_rtx_SET (VOIDmode, temp3,
+                             gen_rtx_ASHIFT (DImode, temp2, GEN_INT (12))));
+      emit_insn (gen_setl44 (op0, temp3, op1));
       break;
 
     case CM_MEDANY:
@@ -1499,29 +1727,44 @@ sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp1)
         sethi  %hh(symbol), %temp1
         sethi  %lm(symbol), %temp2
         or     %temp1, %hm(symbol), %temp3
-        or     %temp2, %lo(symbol), %temp4
-        sllx   %temp3, 32, %temp5
-        or     %temp4, %temp5, %reg  */
-
-      /* It is possible that one of the registers we got for operands[2]
-        might coincide with that of operands[0] (which is why we made
-        it TImode).  Pick the other one to use as our scratch.  */
-      if (rtx_equal_p (temp1, op0))
+        sllx   %temp3, 32, %temp4
+        or     %temp4, %temp2, %temp5
+        or     %temp5, %lo(symbol), %reg  */
+      if (temp)
        {
-         if (ti_temp1)
-           temp1 = gen_rtx_REG (DImode, REGNO (temp1) + 1);
-         else
-           abort();
+         /* It is possible that one of the registers we got for operands[2]
+            might coincide with that of operands[0] (which is why we made
+            it TImode).  Pick the other one to use as our scratch.  */
+         if (rtx_equal_p (temp, op0))
+           {
+             if (ti_temp)
+               temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
+             else
+               abort();
+           }
+         temp1 = op0;
+         temp2 = temp;  /* op0 is _not_ allowed, see above.  */
+         temp3 = op0;
+         temp4 = op0;
+         temp5 = op0;
+       }
+      else
+       {
+         temp1 = gen_reg_rtx (DImode);
+         temp2 = gen_reg_rtx (DImode);
+         temp3 = gen_reg_rtx (DImode);
+         temp4 = gen_reg_rtx (DImode);
+         temp5 = gen_reg_rtx (DImode);
        }
 
-      emit_insn (gen_sethh (op0, op1));
-      emit_insn (gen_setlm (temp1, op1));
-      emit_insn (gen_sethm (op0, op0, op1));
-      emit_insn (gen_rtx_SET (VOIDmode, op0,
-                             gen_rtx_ASHIFT (DImode, op0, GEN_INT (32))));
-      emit_insn (gen_rtx_SET (VOIDmode, op0,
-                             gen_rtx_PLUS (DImode, op0, temp1)));
-      emit_insn (gen_setlo (op0, op0, op1));
+      emit_insn (gen_sethh (temp1, op1));
+      emit_insn (gen_setlm (temp2, op1));
+      emit_insn (gen_sethm (temp3, temp1, op1));
+      emit_insn (gen_rtx_SET (VOIDmode, temp4,
+                             gen_rtx_ASHIFT (DImode, temp3, GEN_INT (32))));
+      emit_insn (gen_rtx_SET (VOIDmode, temp5,
+                             gen_rtx_PLUS (DImode, temp4, temp2)));
+      emit_insn (gen_setlo (op0, temp5, op1));
       break;
 
     case CM_EMBMEDANY:
@@ -1533,42 +1776,69 @@ sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp1)
         look different.
 
         Data segment:  sethi   %hi(symbol), %temp1
-                       or      %temp1, %lo(symbol), %temp2
-                       add     %temp2, EMBMEDANY_BASE_REG, %reg
-
-        Text segment:  sethi   %uhi(symbol), %temp1
-                       sethi   %hi(symbol), %temp2
-                       or      %temp1, %ulo(symbol), %temp3
-                       or      %temp2, %lo(symbol), %temp4
-                       sllx    %temp3, 32, %temp5
-                       or      %temp4, %temp5, %reg  */
+                       add     %temp1, EMBMEDANY_BASE_REG, %temp2
+                       or      %temp2, %lo(symbol), %reg  */
       if (data_segment_operand (op1, GET_MODE (op1)))
        {
+         if (temp)
+           {
+             temp1 = temp;  /* op0 is allowed.  */
+             temp2 = op0;
+           }
+         else
+           {
+             temp1 = gen_reg_rtx (DImode);
+             temp2 = gen_reg_rtx (DImode);
+           }
+
          emit_insn (gen_embmedany_sethi (temp1, op1));
-         emit_insn (gen_embmedany_brsum (op0, temp1));
-         emit_insn (gen_embmedany_losum (op0, op0, op1));
+         emit_insn (gen_embmedany_brsum (temp2, temp1));
+         emit_insn (gen_embmedany_losum (op0, temp2, op1));
        }
+
+      /* Text segment: sethi   %uhi(symbol), %temp1
+                       sethi   %hi(symbol), %temp2
+                       or      %temp1, %ulo(symbol), %temp3
+                       sllx    %temp3, 32, %temp4
+                       or      %temp4, %temp2, %temp5
+                       or      %temp5, %lo(symbol), %reg  */
       else
        {
-         /* It is possible that one of the registers we got for operands[2]
-            might coincide with that of operands[0] (which is why we made
-            it TImode).  Pick the other one to use as our scratch.  */
-         if (rtx_equal_p (temp1, op0))
+         if (temp)
            {
-             if (ti_temp1)
-               temp1 = gen_rtx_REG (DImode, REGNO (temp1) + 1);
-             else
-               abort();
+             /* It is possible that one of the registers we got for operands[2]
+                might coincide with that of operands[0] (which is why we made
+                it TImode).  Pick the other one to use as our scratch.  */
+             if (rtx_equal_p (temp, op0))
+               {
+                 if (ti_temp)
+                   temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
+                 else
+                   abort();
+               }
+             temp1 = op0;
+             temp2 = temp;  /* op0 is _not_ allowed, see above.  */
+             temp3 = op0;
+             temp4 = op0;
+             temp5 = op0;
+           }
+         else
+           {
+             temp1 = gen_reg_rtx (DImode);
+             temp2 = gen_reg_rtx (DImode);
+             temp3 = gen_reg_rtx (DImode);
+             temp4 = gen_reg_rtx (DImode);
+             temp5 = gen_reg_rtx (DImode);
            }
 
-         emit_insn (gen_embmedany_textuhi (op0, op1));
-         emit_insn (gen_embmedany_texthi  (temp1, op1));
-         emit_insn (gen_embmedany_textulo (op0, op0, op1));
-         emit_insn (gen_rtx_SET (VOIDmode, op0,
-                                 gen_rtx_ASHIFT (DImode, op0, GEN_INT (32))));
-         emit_insn (gen_rtx_SET (VOIDmode, op0,
-                                 gen_rtx_PLUS (DImode, op0, temp1)));
-         emit_insn (gen_embmedany_textlo  (op0, op0, op1));
+         emit_insn (gen_embmedany_textuhi (temp1, op1));
+         emit_insn (gen_embmedany_texthi  (temp2, op1));
+         emit_insn (gen_embmedany_textulo (temp3, temp1, op1));
+         emit_insn (gen_rtx_SET (VOIDmode, temp4,
+                                 gen_rtx_ASHIFT (DImode, temp3, GEN_INT (32))));
+         emit_insn (gen_rtx_SET (VOIDmode, temp5,
+                                 gen_rtx_PLUS (DImode, temp4, temp2)));
+         emit_insn (gen_embmedany_textlo  (op0, temp5, op1));
        }
       break;
 
@@ -1948,7 +2218,7 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
   unsigned HOST_WIDE_INT high_bits, low_bits;
   int lowest_bit_set, highest_bit_set;
   int all_bits_between_are_set;
-  rtx temp;
+  rtx temp = 0;
 
   /* Sanity check that we know what we are working with.  */
   if (! TARGET_ARCH64)
@@ -1964,8 +2234,6 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
 
   if (reload_in_progress || reload_completed)
     temp = op0;
-  else
-    temp = gen_reg_rtx (DImode);
 
   if (GET_CODE (op1) != CONST_DOUBLE
       && GET_CODE (op1) != CONST_INT)
@@ -1974,6 +2242,9 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
       return;
     }
 
+  if (! temp)
+    temp = gen_reg_rtx (DImode);
+
   if (GET_CODE (op1) == CONST_DOUBLE)
     {
 #if HOST_BITS_PER_WIDE_INT == 64
@@ -2946,7 +3217,7 @@ eligible_for_sibcall_delay (rtx trial)
     {
       /* If the tail call is done using the call instruction,
         we have to restore %o7 in the delay slot.  */
-      if (! SIBCALL_SLOT_EMPTY_P)
+      if (LEAF_SIBCALL_SLOT_RESERVED_P)
        return 0;
 
       /* %g1 is used to build the function address */
@@ -3059,8 +3330,8 @@ sparc_cannot_force_const_mem (rtx x)
 static GTY(()) rtx global_offset_table;
 
 /* The function we use to get at it.  */
-static GTY(()) rtx get_pc_symbol;
-static GTY(()) char get_pc_symbol_name[256];
+static GTY(()) rtx add_pc_to_pic_symbol;
+static GTY(()) char add_pc_to_pic_symbol_name[256];
 
 /* Ensure that we are not using patterns that are not OK with PIC.  */
 
@@ -3534,11 +3805,10 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
       else
        address = orig;
 
-      pic_ref = gen_rtx_MEM (Pmode,
-                            gen_rtx_PLUS (Pmode,
-                                          pic_offset_table_rtx, address));
+      pic_ref = gen_const_mem (Pmode,
+                              gen_rtx_PLUS (Pmode,
+                                            pic_offset_table_rtx, address));
       current_function_uses_pic_offset_table = 1;
-      RTX_UNCHANGING_P (pic_ref) = 1;
       insn = emit_move_insn (reg, pic_ref);
       /* Put a REG_EQUAL note on this insn, so that it can be optimized
         by loop.  */
@@ -3643,33 +3913,37 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
 static void
 load_pic_register (void)
 {
-  /* Labels to get the PC in the prologue of this function.  */
   int orig_flag_pic = flag_pic;
 
-  /* If we haven't emitted the special get_pc helper function, do so now.  */
-  if (get_pc_symbol_name[0] == 0)
+  /* If we haven't emitted the special helper function, do so now.  */
+  if (add_pc_to_pic_symbol_name[0] == 0)
     {
+      const char *pic_name = reg_names[REGNO (pic_offset_table_rtx)];
       int align;
 
-      ASM_GENERATE_INTERNAL_LABEL (get_pc_symbol_name, "LGETPC", 0);
+      ASM_GENERATE_INTERNAL_LABEL (add_pc_to_pic_symbol_name, "LADDPC", 0);
       text_section ();
 
       align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
       if (align > 0)
        ASM_OUTPUT_ALIGN (asm_out_file, align);
-      (*targetm.asm_out.internal_label) (asm_out_file, "LGETPC", 0);
-      fputs ("\tretl\n\tadd\t%o7, %l7, %l7\n", asm_out_file);
+      ASM_OUTPUT_LABEL (asm_out_file, add_pc_to_pic_symbol_name);
+      if (flag_delayed_branch)
+       fprintf (asm_out_file, "\tjmp %%o7+8\n\t add\t%%o7, %s, %s\n",
+                pic_name, pic_name);
+      else
+       fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp %%o7+8\n\t nop\n",
+                pic_name, pic_name);
     }
 
   /* Initialize every time through, since we can't easily
      know this to be permanent.  */
   global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
-  get_pc_symbol = gen_rtx_SYMBOL_REF (Pmode, get_pc_symbol_name);
-  flag_pic = 0;
-
-  emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
-                        get_pc_symbol));
+  add_pc_to_pic_symbol = gen_rtx_SYMBOL_REF (Pmode, add_pc_to_pic_symbol_name);
 
+  flag_pic = 0;
+  emit_insn (gen_load_pcrel_sym (pic_offset_table_rtx, global_offset_table,
+                                add_pc_to_pic_symbol));
   flag_pic = orig_flag_pic;
 
   /* Need to emit this whether or not we obey regdecls,
@@ -4355,17 +4629,16 @@ sparc_asm_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 /* Output a 'restore' instruction.  */
  
 static void
-output_restore (rtx insn)
+output_restore (rtx pat)
 {
-  rtx operands[3], pat;
+  rtx operands[3];
 
-  if (! insn)
+  if (! pat)
     {
       fputs ("\t restore\n", asm_out_file);
       return;
     }
 
-  pat = PATTERN (insn);
   if (GET_CODE (pat) != SET)
     abort ();
 
@@ -4434,7 +4707,7 @@ output_return (rtx insn)
          if (! delay)
            abort ();
 
-         final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
+         final_scan_insn (delay, asm_out_file, 1, 0, 2, NULL);
          PATTERN (delay) = gen_blockage ();
          INSN_CODE (delay) = -1;
        }
@@ -4455,12 +4728,18 @@ output_return (rtx insn)
          if (delay_slot_filled_p || sparc_skip_caller_unimp)
            abort ();
 
+         if (! flag_delayed_branch)
+           fputs ("\tadd\t%fp, %g1, %fp\n", asm_out_file);
+
          if (TARGET_V9)
            fputs ("\treturn\t%i7+8\n", asm_out_file);
          else
            fputs ("\trestore\n\tjmp\t%o7+8\n", asm_out_file);
 
-         fputs ("\t add\t%sp, %g1, %sp\n", asm_out_file);
+         if (flag_delayed_branch)
+           fputs ("\t add\t%sp, %g1, %sp\n", asm_out_file);
+         else
+           fputs ("\t nop\n", asm_out_file);
        }
       else if (delay_slot_filled_p)
        {
@@ -4477,13 +4756,13 @@ output_return (rtx insn)
              epilogue_renumber (&pat, 0);
              fprintf (asm_out_file, "\treturn\t%%i7+%d\n",
                       sparc_skip_caller_unimp ? 12 : 8);
-             final_scan_insn (delay, asm_out_file, 1, 0, 0, NULL);
+             final_scan_insn (delay, asm_out_file, 1, 0, 2, NULL);
            }
          else
            {
              fprintf (asm_out_file, "\tjmp\t%%i7+%d\n",
                       sparc_skip_caller_unimp ? 12 : 8);
-             output_restore (delay);
+             output_restore (pat);
            }
 
          PATTERN (delay) = gen_blockage ();
@@ -4495,9 +4774,12 @@ output_return (rtx insn)
          if (TARGET_V9)
            fprintf (asm_out_file, "\treturn\t%%i7+%d\n\t nop\n",
                     sparc_skip_caller_unimp ? 12 : 8);
-         else
+         else if (flag_delayed_branch)
            fprintf (asm_out_file, "\tjmp\t%%i7+%d\n\t restore\n",
                     sparc_skip_caller_unimp ? 12 : 8);
+         else
+           fprintf (asm_out_file, "\trestore\n\tjmp\t%%o7+%d\n\t nop\n",
+                    sparc_skip_caller_unimp ? 12 : 8);
        }
     }
 
@@ -4513,6 +4795,9 @@ output_sibcall (rtx insn, rtx call_operand)
   bool delay_slot_filled_p = dbr_sequence_length () > 0;
   rtx operands[1];
 
+  if (! flag_delayed_branch)
+    abort();
+
   operands[0] = call_operand;
 
   if (leaf_function_p)
@@ -4521,7 +4806,7 @@ output_sibcall (rtx insn, rtx call_operand)
         register window.  We simply output the jump to the function and
         the insn in the delay slot (if any).  */
 
-      if (! SIBCALL_SLOT_EMPTY_P && delay_slot_filled_p)
+      if (LEAF_SIBCALL_SLOT_RESERVED_P && delay_slot_filled_p)
        abort();
 
       if (delay_slot_filled_p)
@@ -4532,7 +4817,7 @@ output_sibcall (rtx insn, rtx call_operand)
 
          output_asm_insn ("sethi\t%%hi(%a0), %%g1", operands);
          output_asm_insn ("jmp\t%%g1 + %%lo(%a0)", operands);
-         final_scan_insn (delay, asm_out_file, 1, 0, 0, NULL);
+         final_scan_insn (delay, asm_out_file, 1, 0, 2, NULL);
 
          PATTERN (delay) = gen_blockage ();
          INSN_CODE (delay) = -1;
@@ -4560,13 +4845,13 @@ output_sibcall (rtx insn, rtx call_operand)
          if (! delay)
            abort ();
 
-         output_restore (delay);
+         output_restore (PATTERN (delay));
 
          PATTERN (delay) = gen_blockage ();
          INSN_CODE (delay) = -1;
        }
       else
-       output_restore (0);
+       output_restore (NULL_RTX);
     }
 
   return "";
@@ -5446,8 +5731,8 @@ function_arg_partial_nregs (const struct sparc_args *cum,
     }
   else
     {
-      /* We are guaranteed by function_arg_pass_by_reference that the size
-        of the argument is not greater than 16 bytes, so we only need to
+      /* We are guaranteed by pass_by_reference that the size of the
+        argument is not greater than 16 bytes, so we only need to
         return 1 if the argument is partially passed in registers.  */
 
       if (type && AGGREGATE_TYPE_P (type))
@@ -5478,16 +5763,16 @@ function_arg_partial_nregs (const struct sparc_args *cum,
   return 0;
 }
 
-/* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
+/* Return true if the argument should be passed by reference.
    !v9: The SPARC ABI stipulates passing struct arguments (of any size) and
    quad-precision floats by invisible reference.
    v9: Aggregates greater than 16 bytes are passed by reference.
    For Pascal, also pass arrays by reference.  */
 
-int
-function_arg_pass_by_reference (const struct sparc_args *cum ATTRIBUTE_UNUSED,
-                               enum machine_mode mode, tree type,
-                               int named ATTRIBUTE_UNUSED)
+static bool
+sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+                        enum machine_mode mode, tree type,
+                        bool named ATTRIBUTE_UNUSED)
 {
   if (TARGET_ARCH32)
     {
@@ -5668,6 +5953,18 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
            abort (); /* shouldn't get here */
 
          mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
+
+         /* ??? We probably should have made the same ABI change in
+            3.4.0 as the one we made for unions.   The latter was
+            required by the SCD though, while the former is not
+            specified, so we favored compatibility and efficiency.
+
+            Now we're stuck for aggregates larger than 16 bytes,
+            because OImode vanished in the meantime.  Let's not
+            try to be unduly clever, and simply follow the ABI
+            for unions in that case.  */
+         if (mode == BLKmode)
+           return function_arg_union_value (bytes, mode, regbase);
        }
       else if (GET_MODE_CLASS (mode) == MODE_INT
               && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
@@ -5722,7 +6019,7 @@ sparc_va_start (tree valist, rtx nextarg)
 
 /* Implement `va_arg' for stdarg.  */
 
-tree
+static tree
 sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
 {
   HOST_WIDE_INT size, rsize, align;
@@ -5730,7 +6027,7 @@ sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   bool indirect;
   tree ptrtype = build_pointer_type (type);
 
-  if (function_arg_pass_by_reference (0, TYPE_MODE (type), type, 0))
+  if (pass_by_reference (NULL, TYPE_MODE (type), type, 0))
     {
       indirect = true;
       size = rsize = UNITS_PER_WORD;
@@ -5812,18 +6109,77 @@ sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   return build_fold_indirect_ref (addr);
 }
 \f
+/* Return the string to output an unconditional branch to LABEL, which is
+   the operand number of the label.
+
+   DEST is the destination insn (i.e. the label), INSN is the source.  */
+
+const char *
+output_ubranch (rtx dest, int label, rtx insn)
+{
+  static char string[64];
+  bool noop = false;
+  char *p;
+
+  /* TurboSPARC is reported to have problems with
+     with
+       foo: b,a foo
+     i.e. an empty loop with the annul bit set.  The workaround is to use 
+        foo: b foo; nop
+     instead.  */
+
+  if (! TARGET_V9 && flag_delayed_branch
+      && (INSN_ADDRESSES (INSN_UID (dest))
+         == INSN_ADDRESSES (INSN_UID (insn))))
+    {
+      strcpy (string, "b\t");
+      noop = true;
+    }
+  else
+    {
+      bool v9_form = false;
+
+      if (TARGET_V9 && INSN_ADDRESSES_SET_P ())
+       {
+         int delta = (INSN_ADDRESSES (INSN_UID (dest))
+                      - INSN_ADDRESSES (INSN_UID (insn)));
+         /* Leave some instructions for "slop".  */
+         if (delta >= -260000 && delta < 260000)
+           v9_form = true;
+       }
+
+      if (v9_form)
+       strcpy (string, "ba%*,pt\t%%xcc, ");
+      else
+       strcpy (string, "b%*\t");
+    }
+
+  p = strchr (string, '\0');
+  *p++ = '%';
+  *p++ = 'l';
+  *p++ = '0' + label;
+  *p++ = '%';
+  if (noop)
+    *p++ = '#';
+  else
+    *p++ = '(';
+  *p = '\0';
+
+  return string;
+}
+
 /* Return the string to output a conditional branch to LABEL, which is
    the operand number of the label.  OP is the conditional expression.
    XEXP (OP, 0) is assumed to be a condition code register (integer or
    floating point) and its mode specifies what kind of comparison we made.
 
+   DEST is the destination insn (i.e. the label), INSN is the source.
+
    REVERSED is nonzero if we should reverse the sense of the comparison.
 
    ANNUL is nonzero if we should generate an annulling branch.
 
-   NOOP is nonzero if we have to follow this branch by a noop.
-
-   INSN, if set, is the insn.  */
+   NOOP is nonzero if we have to follow this branch by a noop.  */
 
 const char *
 output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
@@ -5858,7 +6214,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
       nop
      ba .LC29  */
 
-  far = get_attr_length (insn) >= 3;
+  far = TARGET_V9 && (get_attr_length (insn) >= 3);
   if (reversed ^ far)
     {
       /* Reversal of FP compares takes care -- an ordered compare
@@ -5988,9 +6344,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
       spaces -= 2;
     }
 
-  if (! TARGET_V9)
-    labelno = "";
-  else
+  if (TARGET_V9)
     {
       rtx note;
       int v8 = 0;
@@ -6040,6 +6394,9 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
          spaces -= 3;
        }
     }
+  else
+    labelno = "";
+
   if (spaces > 0)
     *p++ = '\t';
   else
@@ -6283,6 +6640,8 @@ sparc_emit_fixunsdi (rtx *operands, enum machine_mode mode)
    operand number of the reg.  OP is the conditional expression.  The mode
    of REG says what kind of comparison we made.
 
+   DEST is the destination insn (i.e. the label), INSN is the source.
+
    REVERSED is nonzero if we should reverse the sense of the comparison.
 
    ANNUL is nonzero if we should generate an annulling branch.
@@ -7236,7 +7595,7 @@ sparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
 
   /* Call __enable_execute_stack after writing onto the stack to make sure
      the stack address is accessible.  */
-#ifdef TRANSFER_FROM_TRAMPOLINE
+#ifdef ENABLE_EXECUTE_STACK
   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
                      LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
 #endif
@@ -7277,7 +7636,7 @@ sparc64_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
 
   /* Call __enable_execute_stack after writing onto the stack to make sure
      the stack address is accessible.  */
-#ifdef TRANSFER_FROM_TRAMPOLINE
+#ifdef ENABLE_EXECUTE_STACK
   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
                      LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
 #endif
@@ -7450,18 +7809,6 @@ sparc_sched_init (FILE *dump ATTRIBUTE_UNUSED,
 }
   
 static int
-sparc_use_dfa_pipeline_interface (void)
-{
-  if ((1 << sparc_cpu) &
-      ((1 << PROCESSOR_ULTRASPARC) | (1 << PROCESSOR_CYPRESS) |
-       (1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) |
-       (1 << PROCESSOR_SPARCLITE86X) | (1 << PROCESSOR_TSC701) |
-       (1 << PROCESSOR_ULTRASPARC3)))
-    return 1;
-  return 0;
-}
-
-static int
 sparc_use_sched_lookahead (void)
 {
   if (sparc_cpu == PROCESSOR_ULTRASPARC
@@ -7801,7 +8148,10 @@ sparc_elf_asm_named_section (const char *name, unsigned int flags)
 #endif /* OBJECT_FORMAT_ELF */
 
 /* We do not allow indirect calls to be optimized into sibling calls.
-   
+
+   We cannot use sibling calls when delayed branches are disabled
+   because they will likely require the call delay slot to be filled.
+
    Also, on SPARC 32-bit we cannot emit a sibling call when the
    current function returns a structure.  This is because the "unimp
    after call" convention would cause the callee to return to the
@@ -7811,14 +8161,16 @@ sparc_elf_asm_named_section (const char *name, unsigned int flags)
    It may seem strange how this last case could occur.  Usually there
    is code after the call which jumps to epilogue code which dumps the
    return value into the struct return area.  That ought to invalidate
-   the sibling call right?  Well, in the c++ case we can end up passing
+   the sibling call right?  Well, in the C++ case we can end up passing
    the pointer to the struct return area to a constructor (which returns
    void) and then nothing else happens.  Such a sibling call would look
    valid without the added check here.  */
 static bool
 sparc_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
-  return (decl && (TARGET_ARCH64 || ! current_function_returns_struct));
+  return (decl
+         && flag_delayed_branch
+         && (TARGET_ARCH64 || ! current_function_returns_struct));
 }
 \f
 /* libfunc renaming.  */
@@ -7984,368 +8336,205 @@ sparc_extra_constraint_check (rtx op, int c, int strict)
 static bool
 sparc_rtx_costs (rtx x, int code, int outer_code, int *total)
 {
+  enum machine_mode mode = GET_MODE (x);
+  bool float_mode_p = FLOAT_MODE_P (mode);
+
   switch (code)
     {
-    case PLUS: case MINUS: case ABS: case NEG:
-    case FLOAT: case UNSIGNED_FLOAT:
-    case FIX: case UNSIGNED_FIX:
-    case FLOAT_EXTEND: case FLOAT_TRUNCATE:
-      if (FLOAT_MODE_P (GET_MODE (x)))
-       {
-         switch (sparc_cpu)
-           {
-           case PROCESSOR_ULTRASPARC:
-           case PROCESSOR_ULTRASPARC3:
-             *total = COSTS_N_INSNS (4);
-             return true;
-
-           case PROCESSOR_SUPERSPARC:
-             *total = COSTS_N_INSNS (3);
-             return true;
-
-           case PROCESSOR_CYPRESS:
-             *total = COSTS_N_INSNS (5);
-             return true;
-
-           case PROCESSOR_HYPERSPARC:
-           case PROCESSOR_SPARCLITE86X:
-           default:
-             *total = COSTS_N_INSNS (1);
-             return true;
-           }
-       }
-
-      *total = COSTS_N_INSNS (1);
-      return true;
-
-    case SQRT:
-      switch (sparc_cpu)
+    case CONST_INT:
+      if (INTVAL (x) < 0x1000 && INTVAL (x) >= -0x1000)
        {
-       case PROCESSOR_ULTRASPARC:
-         if (GET_MODE (x) == SFmode)
-           *total = COSTS_N_INSNS (13);
-         else
-           *total = COSTS_N_INSNS (23);
-         return true;
-
-       case PROCESSOR_ULTRASPARC3:
-         if (GET_MODE (x) == SFmode)
-           *total = COSTS_N_INSNS (20);
-         else
-           *total = COSTS_N_INSNS (29);
-         return true;
-
-       case PROCESSOR_SUPERSPARC:
-         *total = COSTS_N_INSNS (12);
-         return true;
-
-       case PROCESSOR_CYPRESS:
-         *total = COSTS_N_INSNS (63);
-         return true;
-
-       case PROCESSOR_HYPERSPARC:
-       case PROCESSOR_SPARCLITE86X:
-         *total = COSTS_N_INSNS (17);
-         return true;
-
-       default:
-         *total = COSTS_N_INSNS (30);
+         *total = 0;
          return true;
        }
+      /* FALLTHRU */
 
-    case COMPARE:
-      if (FLOAT_MODE_P (GET_MODE (x)))
-       {
-         switch (sparc_cpu)
-           {
-           case PROCESSOR_ULTRASPARC:
-           case PROCESSOR_ULTRASPARC3:
-             *total = COSTS_N_INSNS (1);
-             return true;
-
-           case PROCESSOR_SUPERSPARC:
-             *total = COSTS_N_INSNS (3);
-             return true;
-
-           case PROCESSOR_CYPRESS:
-             *total = COSTS_N_INSNS (5);
-             return true;
-
-           case PROCESSOR_HYPERSPARC:
-           case PROCESSOR_SPARCLITE86X:
-           default:
-             *total = COSTS_N_INSNS (1);
-             return true;
-           }
-       }
+    case HIGH:
+      *total = 2;
+      return true;
 
-      /* ??? Maybe mark integer compares as zero cost on
-        ??? all UltraSPARC processors because the result
-        ??? can be bypassed to a branch in the same group.  */
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+      *total = 4;
+      return true;
 
-      *total = COSTS_N_INSNS (1);
+    case CONST_DOUBLE:
+      if (GET_MODE (x) == DImode
+         && ((XINT (x, 3) == 0
+              && (unsigned HOST_WIDE_INT) XINT (x, 2) < 0x1000)
+             || (XINT (x, 3) == -1
+                 && XINT (x, 2) < 0
+                 && XINT (x, 2) >= -0x1000)))
+       *total = 0;
+      else
+       *total = 8;
       return true;
 
-    case MULT:
-      if (FLOAT_MODE_P (GET_MODE (x)))
+    case MEM:
+      /* If outer-code was a sign or zero extension, a cost
+        of COSTS_N_INSNS (1) was already added in.  This is
+        why we are subtracting it back out.  */
+      if (outer_code == ZERO_EXTEND)
        {
-         switch (sparc_cpu)
-           {
-           case PROCESSOR_ULTRASPARC:
-           case PROCESSOR_ULTRASPARC3:
-             *total = COSTS_N_INSNS (4);
-             return true;
-
-           case PROCESSOR_SUPERSPARC:
-             *total = COSTS_N_INSNS (3);
-             return true;
-
-           case PROCESSOR_CYPRESS:
-             *total = COSTS_N_INSNS (7);
-             return true;
-
-           case PROCESSOR_HYPERSPARC:
-           case PROCESSOR_SPARCLITE86X:
-             *total = COSTS_N_INSNS (1);
-             return true;
-
-           default:
-             *total = COSTS_N_INSNS (5);
-             return true;
-           }
+         *total = sparc_costs->int_zload - COSTS_N_INSNS (1);
        }
-
-      /* The latency is actually variable for Ultra-I/II
-        And if one of the inputs have a known constant
-        value, we could calculate this precisely.
-
-        However, for that to be useful we would need to
-        add some machine description changes which would
-        make sure small constants ended up in rs1 of the
-        multiply instruction.  This is because the multiply
-        latency is determined by the number of clear (or
-        set if the value is negative) bits starting from
-        the most significant bit of the first input.
-
-        The algorithm for computing num_cycles of a multiply
-        on Ultra-I/II is:
-
-               if (rs1 < 0)
-                       highest_bit = highest_clear_bit(rs1);
-               else
-                       highest_bit = highest_set_bit(rs1);
-               if (num_bits < 3)
-                       highest_bit = 3;
-               num_cycles = 4 + ((highest_bit - 3) / 2);
-
-        If we did that we would have to also consider register
-        allocation issues that would result from forcing such
-        a value into a register.
-
-        There are other similar tricks we could play if we
-        knew, for example, that one input was an array index.
-
-        Since we do not play any such tricks currently the
-        safest thing to do is report the worst case latency.  */
-      if (sparc_cpu == PROCESSOR_ULTRASPARC)
+      else if (outer_code == SIGN_EXTEND)
        {
-         *total = (GET_MODE (x) == DImode
-                   ? COSTS_N_INSNS (34) : COSTS_N_INSNS (19));
-         return true;
+         *total = sparc_costs->int_sload - COSTS_N_INSNS (1);
        }
-
-      /* Multiply latency on Ultra-III, fortunately, is constant.  */
-      if (sparc_cpu == PROCESSOR_ULTRASPARC3)
+      else if (float_mode_p)
        {
-         *total = COSTS_N_INSNS (6);
-         return true;
+         *total = sparc_costs->float_load;
        }
-
-      if (sparc_cpu == PROCESSOR_HYPERSPARC
-         || sparc_cpu == PROCESSOR_SPARCLITE86X)
+      else
        {
-         *total = COSTS_N_INSNS (17);
-         return true;
+         *total = sparc_costs->int_load;
        }
 
-      *total = (TARGET_HARD_MUL ? COSTS_N_INSNS (5) : COSTS_N_INSNS (25));
       return true;
 
-    case DIV:
-    case UDIV:
-    case MOD:
-    case UMOD:
-      if (FLOAT_MODE_P (GET_MODE (x)))
-       {
-         switch (sparc_cpu)
-           {
-           case PROCESSOR_ULTRASPARC:
-             if (GET_MODE (x) == SFmode)
-               *total = COSTS_N_INSNS (13);
-             else
-               *total = COSTS_N_INSNS (23);
-             return true;
+    case PLUS:
+    case MINUS:
+      if (float_mode_p)
+       *total = sparc_costs->float_plusminus;
+      else
+       *total = COSTS_N_INSNS (1);
+      return false;
 
-           case PROCESSOR_ULTRASPARC3:
-             if (GET_MODE (x) == SFmode)
-               *total = COSTS_N_INSNS (17);
-             else
-               *total = COSTS_N_INSNS (20);
-             return true;
+    case MULT:
+      if (float_mode_p)
+       *total = sparc_costs->float_mul;
+      else if (! TARGET_HARD_MUL)
+       *total = COSTS_N_INSNS (25);
+      else
+       {
+         int bit_cost;
 
-           case PROCESSOR_SUPERSPARC:
-             if (GET_MODE (x) == SFmode)
-               *total = COSTS_N_INSNS (6);
-             else
-               *total = COSTS_N_INSNS (9);
-             return true;
+         bit_cost = 0;
+         if (sparc_costs->int_mul_bit_factor)
+           {
+             int nbits;
 
-           case PROCESSOR_HYPERSPARC:
-           case PROCESSOR_SPARCLITE86X:
-             if (GET_MODE (x) == SFmode)
-               *total = COSTS_N_INSNS (8);
+             if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+               {
+                 unsigned HOST_WIDE_INT value = INTVAL (XEXP (x, 1));
+                 for (nbits = 0; value != 0; value &= value - 1)
+                   nbits++;
+               }
+             else if (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
+                      && GET_MODE (XEXP (x, 1)) == DImode)
+               {
+                 rtx x1 = XEXP (x, 1);
+                 unsigned HOST_WIDE_INT value1 = XINT (x1, 2);
+                 unsigned HOST_WIDE_INT value2 = XINT (x1, 3);
+
+                 for (nbits = 0; value1 != 0; value1 &= value1 - 1)
+                   nbits++;
+                 for (; value2 != 0; value2 &= value2 - 1)
+                   nbits++;
+               }
              else
-               *total = COSTS_N_INSNS (12);
-             return true;
+               nbits = 7;
 
-           default:
-             *total = COSTS_N_INSNS (7);
-             return true;
+             if (nbits < 3)
+               nbits = 3;
+             bit_cost = (nbits - 3) / sparc_costs->int_mul_bit_factor;
+             bit_cost = COSTS_N_INSNS (bit_cost);
            }
+
+         if (mode == DImode)
+           *total = sparc_costs->int_mulX + bit_cost;
+         else
+           *total = sparc_costs->int_mul + bit_cost;
        }
+      return false;
 
-      if (sparc_cpu == PROCESSOR_ULTRASPARC)
-       *total = (GET_MODE (x) == DImode
-                 ? COSTS_N_INSNS (68) : COSTS_N_INSNS (37));
-      else if (sparc_cpu == PROCESSOR_ULTRASPARC3)
-       *total = (GET_MODE (x) == DImode
-                 ? COSTS_N_INSNS (71) : COSTS_N_INSNS (40));
-      else
-       *total = COSTS_N_INSNS (25);
-      return true;
+    case ASHIFT:
+    case ASHIFTRT:
+    case LSHIFTRT:
+      *total = COSTS_N_INSNS (1) + sparc_costs->shift_penalty;
+      return false;
 
-    case IF_THEN_ELSE:
-      /* Conditional moves.  */
-      switch (sparc_cpu)
+    case DIV:
+    case UDIV:
+    case MOD:
+    case UMOD:
+      if (float_mode_p)
        {
-       case PROCESSOR_ULTRASPARC:
-         *total = COSTS_N_INSNS (2);
-         return true;
-
-       case PROCESSOR_ULTRASPARC3:
-         if (FLOAT_MODE_P (GET_MODE (x)))
-           *total = COSTS_N_INSNS (3);
+         if (mode == DFmode)
+           *total = sparc_costs->float_div_df;
          else
-           *total = COSTS_N_INSNS (2);
-         return true;
-
-       default:
-         *total = COSTS_N_INSNS (1);
-         return true;
+           *total = sparc_costs->float_div_sf;
        }
-
-    case MEM:
-      /* If outer-code is SIGN/ZERO extension we have to subtract
-        out COSTS_N_INSNS (1) from whatever we return in determining
-        the cost.  */
-      switch (sparc_cpu)
+      else
        {
-       case PROCESSOR_ULTRASPARC:
-         if (outer_code == ZERO_EXTEND)
-           *total = COSTS_N_INSNS (1);
-         else
-           *total = COSTS_N_INSNS (2);
-         return true;
-
-       case PROCESSOR_ULTRASPARC3:
-         if (outer_code == ZERO_EXTEND)
-           {
-             if (GET_MODE (x) == QImode
-                 || GET_MODE (x) == HImode
-                 || outer_code == SIGN_EXTEND)
-               *total = COSTS_N_INSNS (2);
-             else
-               *total = COSTS_N_INSNS (1);
-           }
-         else
-           {
-             /* This handles sign extension (3 cycles)
-                and everything else (2 cycles).  */
-             *total = COSTS_N_INSNS (2);
-           }
-         return true;
-
-       case PROCESSOR_SUPERSPARC:
-         if (FLOAT_MODE_P (GET_MODE (x))
-             || outer_code == ZERO_EXTEND
-             || outer_code == SIGN_EXTEND)
-           *total = COSTS_N_INSNS (0);
-         else
-           *total = COSTS_N_INSNS (1);
-         return true;
-
-       case PROCESSOR_TSC701:
-         if (outer_code == ZERO_EXTEND
-             || outer_code == SIGN_EXTEND)
-           *total = COSTS_N_INSNS (2);
-         else
-           *total = COSTS_N_INSNS (3);
-         return true;
-         
-       case PROCESSOR_CYPRESS:
-         if (outer_code == ZERO_EXTEND
-             || outer_code == SIGN_EXTEND)
-           *total = COSTS_N_INSNS (1);
-         else
-           *total = COSTS_N_INSNS (2);
-         return true;
-         
-       case PROCESSOR_HYPERSPARC:
-       case PROCESSOR_SPARCLITE86X:
-       default:
-         if (outer_code == ZERO_EXTEND
-             || outer_code == SIGN_EXTEND)
-           *total = COSTS_N_INSNS (0);
+         if (mode == DImode)
+           *total = sparc_costs->int_divX;
          else
-           *total = COSTS_N_INSNS (1);
-         return true;
+           *total = sparc_costs->int_div;
        }
+      return false;
 
-    case CONST_INT:
-      if (INTVAL (x) < 0x1000 && INTVAL (x) >= -0x1000)
+    case NEG:
+      if (! float_mode_p)
        {
-         *total = 0;
-         return true;
+         *total = COSTS_N_INSNS (1);
+         return false;
        }
       /* FALLTHRU */
 
-    case HIGH:
-      *total = 2;
-      return true;
+    case ABS:
+    case FLOAT:
+    case UNSIGNED_FLOAT:
+    case FIX:
+    case UNSIGNED_FIX:
+    case FLOAT_EXTEND:
+    case FLOAT_TRUNCATE:
+      *total = sparc_costs->float_move;
+      return false;
 
-    case CONST:
-    case LABEL_REF:
-    case SYMBOL_REF:
-      *total = 4;
-      return true;
+    case SQRT:
+      if (mode == DFmode)
+       *total = sparc_costs->float_sqrt_df;
+      else
+       *total = sparc_costs->float_sqrt_sf;
+      return false;
 
-    case CONST_DOUBLE:
-      if (GET_MODE (x) == DImode
-         && ((XINT (x, 3) == 0
-              && (unsigned HOST_WIDE_INT) XINT (x, 2) < 0x1000)
-             || (XINT (x, 3) == -1
-                 && XINT (x, 2) < 0
-                 && XINT (x, 2) >= -0x1000)))
-       *total = 0;
+    case COMPARE:
+      if (float_mode_p)
+       *total = sparc_costs->float_cmp;
       else
-       *total = 8;
-      return true;
+       *total = COSTS_N_INSNS (1);
+      return false;
+
+    case IF_THEN_ELSE:
+      if (float_mode_p)
+       *total = sparc_costs->float_cmove;
+      else
+       *total = sparc_costs->int_cmove;
+      return false;
 
     default:
       return false;
     }
 }
 
+/* Emit the sequence of insns SEQ while preserving the register REG.  */
+
+static void
+emit_and_preserve (rtx seq, rtx reg)
+{
+  rtx slot = gen_rtx_MEM (word_mode,
+                         plus_constant (stack_pointer_rtx, SPARC_STACK_BIAS));
+
+  emit_stack_pointer_decrement (GEN_INT (UNITS_PER_WORD));
+  emit_insn (gen_rtx_SET (VOIDmode, slot, reg));
+  emit_insn (seq);
+  emit_insn (gen_rtx_SET (VOIDmode, reg, slot));
+  emit_stack_pointer_increment (GEN_INT (UNITS_PER_WORD));
+}
+
 /* Output code to add DELTA to the first argument, and then jump to FUNCTION.
    Used for C++ multiple inheritance.  */
 
@@ -8355,21 +8544,42 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
                       HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
                       tree function)
 {
-  rtx this, insn, funexp, delta_rtx, tmp;
+  rtx this, insn, funexp, delta_rtx;
+  unsigned int int_arg_first;
 
   reload_completed = 1;
   epilogue_completed = 1;
   no_new_pseudos = 1;
-  current_function_uses_only_leaf_regs = 1;
+  reset_block_changes ();
 
   emit_note (NOTE_INSN_PROLOGUE_END);
 
+  if (flag_delayed_branch)
+    {
+      /* We will emit a regular sibcall below, so we need to instruct
+        output_sibcall that we are in a leaf function.  */
+      current_function_uses_only_leaf_regs = 1;
+
+      /* This will cause final.c to invoke leaf_renumber_regs so we
+        must behave as if we were in a not-yet-leafified function.  */
+      int_arg_first = SPARC_INCOMING_INT_ARG_FIRST;
+    }
+  else
+    {
+      /* We will emit the sibcall manually below, so we will need to
+        manually spill non-leaf registers.  */
+      current_function_uses_only_leaf_regs = 0;
+
+      /* We really are in a leaf function.  */
+      int_arg_first = SPARC_OUTGOING_INT_ARG_FIRST;
+    }
+
   /* Find the "this" pointer.  Normally in %o0, but in ARCH64 if the function
      returns a structure, the structure return pointer is there instead.  */
   if (TARGET_ARCH64 && aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
-    this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST + 1);
+    this = gen_rtx_REG (Pmode, int_arg_first + 1);
   else
-    this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST);
+    this = gen_rtx_REG (Pmode, int_arg_first);
 
   /* Add DELTA.  When possible use a plain add, otherwise load it into
      a register first.  */
@@ -8391,8 +8601,9 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
       delta_rtx = scratch;
     }
 
-  tmp = gen_rtx_PLUS (Pmode, this, delta_rtx);
-  emit_insn (gen_rtx_SET (VOIDmode, this, tmp));
+  emit_insn (gen_rtx_SET (VOIDmode,
+                         this,
+                         gen_rtx_PLUS (Pmode, this, delta_rtx)));
 
   /* Generate a tail call to the target function.  */
   if (! TREE_USED (function))
@@ -8401,9 +8612,67 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
       TREE_USED (function) = 1;
     }
   funexp = XEXP (DECL_RTL (function), 0);
-  funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
-  insn = emit_call_insn (gen_sibcall (funexp));
-  SIBLING_CALL_P (insn) = 1;
+
+  if (flag_delayed_branch)
+    {
+      funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
+      insn = emit_call_insn (gen_sibcall (funexp));
+      SIBLING_CALL_P (insn) = 1;
+    }
+  else
+    {
+      /* The hoops we have to jump through in order to generate a sibcall
+        without using delay slots...  */
+      rtx spill_reg, seq, scratch = gen_rtx_REG (Pmode, 1);
+
+      if (flag_pic)
+        {
+         spill_reg = gen_rtx_REG (word_mode, 15);  /* %o7 */
+         start_sequence ();
+         load_pic_register ();  /* clobbers %o7 */
+         scratch = legitimize_pic_address (funexp, Pmode, scratch);
+         seq = get_insns ();
+         end_sequence ();
+         emit_and_preserve (seq, spill_reg);
+       }
+      else if (TARGET_ARCH32)
+       {
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 scratch,
+                                 gen_rtx_HIGH (SImode, funexp)));
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 scratch,
+                                 gen_rtx_LO_SUM (SImode, scratch, funexp)));
+       }
+      else  /* TARGET_ARCH64 */
+        {
+         switch (sparc_cmodel)
+           {
+           case CM_MEDLOW:
+           case CM_MEDMID:
+             /* The destination can serve as a temporary.  */
+             sparc_emit_set_symbolic_const64 (scratch, funexp, scratch);
+             break;
+
+           case CM_MEDANY:
+           case CM_EMBMEDANY:
+             /* The destination cannot serve as a temporary.  */
+             spill_reg = gen_rtx_REG (DImode, 15);  /* %o7 */
+             start_sequence ();
+             sparc_emit_set_symbolic_const64 (scratch, funexp, spill_reg);
+             seq = get_insns ();
+             end_sequence ();
+             emit_and_preserve (seq, spill_reg);
+             break;
+
+           default:
+             abort();
+           }
+       }
+
+      emit_jump_insn (gen_indirect_jump (scratch));
+    }
+
   emit_barrier ();
 
   /* Run just enough of rest_of_compilation to get the insns emitted.