OSDN Git Service

* config/sparc/sparc.c (sparc_override_options): Do support different
[pf3gnuchains/gcc-fork.git] / gcc / config / sparc / sparc.c
index f7e0c22..4e3dbe6 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines for insn-output.c for Sun SPARC.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   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.
@@ -99,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.
@@ -109,7 +127,6 @@ char leaf_reg_remap[] =
 static const char *frame_base_name;
 static int frame_base_offset;
 
-static rtx pic_setup_code      PARAMS ((void));
 static void sparc_init_modes   PARAMS ((void));
 static int save_regs           PARAMS ((FILE *, int, int, const char *,
                                       int, int, int));
@@ -136,7 +153,8 @@ static rtx *ultra_find_type PARAMS ((int, rtx *, int));
 static void ultra_build_types_avail PARAMS ((rtx *, int));
 static void ultra_flush_pipeline PARAMS ((void));
 static void ultra_rescan_pipeline_state PARAMS ((rtx *, int));
-static int set_extends PARAMS ((rtx, rtx));
+static int set_extends PARAMS ((rtx));
+static void output_restore_regs PARAMS ((FILE *, int));
 \f
 /* Option handling.  */
 
@@ -223,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;
@@ -233,23 +251,10 @@ 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)
-    {
-      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;
-    }
-
   /* We force all 64bit archs to use 128 bit long double */
   if (TARGET_64BIT && ! TARGET_LONG_DOUBLE_128)
     {
@@ -323,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;
@@ -335,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;
@@ -1169,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;
@@ -1807,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
@@ -2458,6 +2475,98 @@ eligible_for_epilogue_delay (trial, slot)
   return 0;
 }
 
+/* Return nonzero if TRIAL can go into the sibling call
+   delay slot.  */
+
+int
+eligible_for_sibcall_delay (trial)
+     rtx trial;
+{
+  rtx pat, src;
+
+  if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
+    return 0;
+
+  if (get_attr_length (trial) != 1 || profile_block_flag == 2)
+    return 0;
+
+  pat = PATTERN (trial);
+
+  if (current_function_uses_only_leaf_regs)
+    {
+      /* If the tail call is done using the call instruction,
+        we have to restore %o7 in the delay slot.  */
+      if ((TARGET_ARCH64 && ! TARGET_CM_MEDLOW) || flag_pic)
+       return 0;
+
+      /* %g1 is used to build the function address */
+      if (reg_mentioned_p (gen_rtx_REG (Pmode, 1), pat))
+       return 0;
+
+      return 1;
+    }
+
+  /* Otherwise, only operations which can be done in tandem with
+     a `restore' insn can go into the delay slot.  */
+  if (GET_CODE (SET_DEST (pat)) != REG
+      || REGNO (SET_DEST (pat)) < 24
+      || REGNO (SET_DEST (pat)) >= 32)
+    return 0;
+
+  /* If it mentions %o7, it can't go in, because sibcall will clobber it
+     in most cases.  */
+  if (reg_mentioned_p (gen_rtx_REG (Pmode, 15), pat))
+    return 0;
+
+  src = SET_SRC (pat);
+
+  if (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;
+}
+
 static int
 check_return_regs (x)
      rtx x;
@@ -2508,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;
 }
 
@@ -2706,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 ();
@@ -2749,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
@@ -2758,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;
 
@@ -2825,10 +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 (((cfun != 0 && REGNO_POINTER_ALIGN (regno) >= desired)
-              || reload_completed)
-             && ((INTVAL (offset) & (desired - 1)) == 0))
+            completed, we already matched with proper alignments.
+            If not running global_alloc, reload might give us
+            unaligned pointer to local stack though.  */
+         if (((cfun != 0
+               && REGNO_POINTER_ALIGN (regno) >= desired * BITS_PER_UNIT)
+              || (optimize && reload_completed))
+             && (INTVAL (offset) & (desired - 1)) == 0)
            return 1;
        }
       else
@@ -3155,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;
        }
@@ -3421,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
@@ -3455,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)
@@ -3573,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.
 
@@ -3699,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;
@@ -3805,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
-       PARAMS ((int, struct function_arg_record_value_parms *));
+       PARAMS ((HOST_WIDE_INT, struct function_arg_record_value_parms *));
 static void function_arg_record_value_2
-       PARAMS ((tree, int, struct function_arg_record_value_parms *));
+       PARAMS ((tree, HOST_WIDE_INT,
+                struct function_arg_record_value_parms *));
 static void function_arg_record_value_1
-        PARAMS ((tree, int, struct function_arg_record_value_parms *));
+        PARAMS ((tree, HOST_WIDE_INT,
+                struct function_arg_record_value_parms *));
 static rtx function_arg_record_value
        PARAMS ((tree, enum machine_mode, int, int, int));
 
 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;
@@ -3848,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
@@ -3894,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;
 
@@ -3919,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;
 
@@ -3945,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;
@@ -3964,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
@@ -4009,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;
@@ -4539,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;
@@ -4571,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);
@@ -4794,7 +5061,7 @@ sparc_emit_float_lib_cmp (x, y, comparison)
      rtx x, y;
      enum rtx_code comparison;
 {
-  char *qpfunc;
+  const char *qpfunc;
   rtx slot0, slot1, result, tem, tem2;
   enum machine_mode mode;
 
@@ -5138,9 +5405,9 @@ output_return (operands)
       else
        {
          if ((actual_fsize & 0x3ff) != 0)
-           return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
+           return "sethi\t%%hi(%a0), %%g1\n\tor\t%%g1, %%lo(%a0), %%g1\n\tretl\n\tadd\t%%sp, %%g1, %%sp";
          else
-           return "sethi %%hi(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
+           return "sethi\t%%hi(%a0), %%g1\n\tretl\n\tadd\t%%sp, %%g1, %%sp";
        }
     }
   else if (TARGET_V9)
@@ -5186,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
@@ -7012,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) |
@@ -7298,7 +7567,7 @@ ultra_flush_pipeline ()
 {
   ultra_cur_hist = (ultra_cur_hist + 1) & (ULTRA_NUM_HIST - 1);
   ultra_cycles_elapsed += 1;
-  bzero ((char *) &ultra_pipe, sizeof ultra_pipe);
+  memset ((char *) &ultra_pipe, 0, sizeof ultra_pipe);
   ultra_pipe.free_slot_mask = 0xf;
 }
 
@@ -7308,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;
@@ -7484,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);
@@ -7643,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;
       }
   }
@@ -7696,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);
 
@@ -7721,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;
     }
@@ -7863,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)
@@ -7896,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;
          }
        }
@@ -7917,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");
 }
 
 
@@ -7968,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);
 }
 
 
@@ -8055,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)
     {
@@ -8074,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);
 
@@ -8095,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);
 
@@ -8182,27 +8473,27 @@ sparc_block_profiler(file, blockno)
     {
       ASM_GENERATE_INTERNAL_LABEL (LPBX, "LPBX", 0);
 
-      fprintf (file, "\tsethi\t%%hi(%s__bb),%%g1\n", user_label_prefix);
-      fprintf (file, "\tsethi\t%%hi(%d),%%g%d\n", blockno, bbreg);
-      fprintf (file, "\tor\t%%g1,%%lo(%s__bb),%%g1\n", user_label_prefix);
-      fprintf (file, "\tor\t%%g%d,%%lo(%d),%%g%d\n", bbreg, blockno, bbreg);
+      fprintf (file, "\tsethi\t%%hi(%s__bb), %%g1\n", user_label_prefix);
+      fprintf (file, "\tsethi\t%%hi(%d), %%g%d\n", blockno, bbreg);
+      fprintf (file, "\tor\t%%g1, %%lo(%s__bb), %%g1\n", user_label_prefix);
+      fprintf (file, "\tor\t%%g%d, %%lo(%d), %%g%d\n", bbreg, blockno, bbreg);
 
-      fprintf (file, "\tst\t%%g%d,[%%g1]\n", bbreg);
+      fprintf (file, "\tst\t%%g%d, [%%g1]\n", bbreg);
 
       fputs ("\tsethi\t%hi(", file);
       assemble_name (file, LPBX);
-      fprintf (file, "),%%g%d\n", bbreg);
+      fprintf (file, "), %%g%d\n", bbreg);
   
-      fputs ("\tor\t%o2,%lo(", file);
+      fputs ("\tor\t%o2, %lo(", file);
       assemble_name (file, LPBX);
-      fprintf (file, "),%%g%d\n", bbreg);
+      fprintf (file, "), %%g%d\n", bbreg);
   
-      fprintf (file, "\tst\t%%g%d,[%%g1+4]\n", bbreg);
-      fprintf (file, "\tmov\t%%o7,%%g%d\n", bbreg);
+      fprintf (file, "\tst\t%%g%d, [%%g1 + 4]\n", bbreg);
+      fprintf (file, "\tmov\t%%o7, %%g%d\n", bbreg);
 
       fprintf (file, "\tcall\t%s__bb_trace_func\n\t nop\n", user_label_prefix);
 
-      fprintf (file, "\tmov\t%%g%d,%%o7\n", bbreg);
+      fprintf (file, "\tmov\t%%g%d, %%o7\n", bbreg);
     }
   else if (profile_block_flag != 0)
     {
@@ -8210,18 +8501,18 @@ sparc_block_profiler(file, blockno)
 
       fputs ("\tsethi\t%hi(", file);
       assemble_name (file, LPBX);
-      fprintf (file, "+%d),%%g1\n", blockno*4);
+      fprintf (file, "+%d), %%g1\n", blockno*4);
 
       fputs ("\tld\t[%g1+%lo(", file);
       assemble_name (file, LPBX);
       if (TARGET_ARCH64 && USE_AS_OFFSETABLE_LO10)
-       fprintf (file, ")+%d],%%g%d\n", blockno*4, bbreg);
+       fprintf (file, ")+%d], %%g%d\n", blockno*4, bbreg);
       else
-       fprintf (file, "+%d)],%%g%d\n", blockno*4, bbreg);
+       fprintf (file, "+%d)], %%g%d\n", blockno*4, bbreg);
 
-      fprintf (file, "\tadd\t%%g%d,1,%%g%d\n", bbreg, bbreg);
+      fprintf (file, "\tadd\t%%g%d, 1, %%g%d\n", bbreg, bbreg);
 
-      fprintf (file, "\tst\t%%g%d,[%%g1+%%lo(", bbreg);
+      fprintf (file, "\tst\t%%g%d, [%%g1+%%lo(", bbreg);
       assemble_name (file, LPBX);
       if (TARGET_ARCH64 && USE_AS_OFFSETABLE_LO10)
        fprintf (file, ")+%d]\n", blockno*4);
@@ -8290,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);
 }