(ctype.h): Delete.
authorJim Wilson <wilson@gcc.gnu.org>
Thu, 18 Jan 1996 22:41:00 +0000 (14:41 -0800)
committerJim Wilson <wilson@gcc.gnu.org>
Thu, 18 Jan 1996 22:41:00 +0000 (14:41 -0800)
(regno_reg_class, reg_class_from_letter, prepare_scc_operands,
broken_move, push, pop, push_regs, calc_live_regs, sh_expand_prologue,
sh_expand_epilogue, initial_elimination_offset, arith_reg_operand):
Add SH3e support.
(sh_builtin_saveregs, fp_zero_operand, fp_one_operand): New functions.
(sh_function_arg, sh_function_arg_partial_nregs): Delete.

From-SVN: r11068

gcc/config/sh/sh.c

index 81125b3e41c11a29cb023db6998538f56a86fa61..1a9cda919c19077413c5265abb51edaac13a0ee0 100644 (file)
@@ -23,7 +23,6 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 
-#include <ctype.h>
 #include <stdio.h>
 
 #include "rtl.h"
@@ -85,7 +84,11 @@ int regno_reg_class[FIRST_PSEUDO_REGISTER] =
   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
   GENERAL_REGS, PR_REGS, T_REGS, NO_REGS,
-  MAC_REGS, MAC_REGS,
+  MAC_REGS, MAC_REGS, FPUL_REGS, NO_REGS,
+  FP0_REGS,FP_REGS, FP_REGS, FP_REGS,
+  FP_REGS, FP_REGS, FP_REGS, FP_REGS,
+  FP_REGS, FP_REGS, FP_REGS, FP_REGS,
+  FP_REGS, FP_REGS, FP_REGS, FP_REGS,
 };
 
 /* Provide reg_class from a letter such as appears in the machine
@@ -94,12 +97,12 @@ int regno_reg_class[FIRST_PSEUDO_REGISTER] =
 enum reg_class reg_class_from_letter[] =
 {
   /* a */ NO_REGS, /* b */ NO_REGS, /* c */ NO_REGS, /* d */ NO_REGS,
-  /* e */ NO_REGS, /* f */ NO_REGS, /* g */ NO_REGS, /* h */ NO_REGS,
+  /* e */ NO_REGS, /* f */ FP_REGS, /* g */ NO_REGS, /* h */ NO_REGS,
   /* i */ NO_REGS, /* j */ NO_REGS, /* k */ NO_REGS, /* l */ PR_REGS,
   /* m */ NO_REGS, /* n */ NO_REGS, /* o */ NO_REGS, /* p */ NO_REGS,
   /* q */ NO_REGS, /* r */ NO_REGS, /* s */ NO_REGS, /* t */ T_REGS,
-  /* u */ NO_REGS, /* v */ NO_REGS, /* w */ NO_REGS, /* x */ MAC_REGS,
-  /* y */ NO_REGS, /* z */ R0_REGS
+  /* u */ NO_REGS, /* v */ NO_REGS, /* w */ FP0_REGS, /* x */ MAC_REGS,
+  /* y */ FPUL_REGS, /* z */ R0_REGS
 };
 \f
 /* Print the operand address in x to the stream.  */
@@ -367,6 +370,8 @@ prepare_scc_operands (code)
          || code == GTU  || code == GEU || code == LTU || code == LEU))
     sh_compare_op1 = force_reg (mode, sh_compare_op1);
 
+  /* ??? This should be `mode' not `SImode' in the compare, but that would
+     require fixing the branch patterns too.  */
   emit_insn (gen_rtx (SET, VOIDmode, t_reg,
                      gen_rtx (code, SImode, sh_compare_op0,
                               sh_compare_op1)));
@@ -1212,6 +1217,12 @@ broken_move (insn)
         order bits end up as.  */
       && GET_MODE (SET_DEST (PATTERN (insn))) != QImode
       && CONSTANT_P (SET_SRC (PATTERN (insn)))
+      && ! (GET_CODE (SET_SRC (PATTERN (insn))) == CONST_DOUBLE
+           && (fp_zero_operand (SET_SRC (PATTERN (insn)))
+               || fp_one_operand (SET_SRC (PATTERN (insn))))
+           && GET_CODE (SET_DEST (PATTERN (insn))) == REG
+           && REGNO (SET_DEST (PATTERN (insn))) >= FIRST_FP_REG
+           && REGNO (SET_DEST (PATTERN (insn))) <= LAST_FP_REG)
       && (GET_CODE (SET_SRC (PATTERN (insn))) != CONST_INT
          || ! CONST_OK_FOR_I (INTVAL (SET_SRC (PATTERN (insn))))))
     return 1;
@@ -1828,7 +1839,12 @@ push (rn)
      int rn;
 {
   rtx x;
-  x = emit_insn (gen_push (gen_rtx (REG, SImode, rn)));
+  if ((rn >= FIRST_FP_REG && rn <= LAST_FP_REG)
+      || rn == FPUL_REG)
+    x = emit_insn (gen_push_e (gen_rtx (REG, SFmode, rn)));
+  else
+    x = emit_insn (gen_push (gen_rtx (REG, SImode, rn)));
+
   REG_NOTES (x) = gen_rtx (EXPR_LIST, REG_INC,
                           gen_rtx(REG, SImode, STACK_POINTER_REGNUM), 0);
 }
@@ -1840,7 +1856,12 @@ pop (rn)
      int rn;
 {
   rtx x;
-  x = emit_insn (gen_pop (gen_rtx (REG, SImode, rn)));
+  if ((rn >= FIRST_FP_REG && rn <= LAST_FP_REG)
+      || rn == FPUL_REG)
+    x = emit_insn (gen_pop_e (gen_rtx (REG, SFmode, rn)));
+  else
+    x = emit_insn (gen_pop (gen_rtx (REG, SImode, rn)));
+    
   REG_NOTES (x) = gen_rtx (EXPR_LIST, REG_INC,
                           gen_rtx(REG, SImode, STACK_POINTER_REGNUM), 0);
 }
@@ -1849,14 +1870,17 @@ pop (rn)
    the number of bytes the insns take.  */
 
 static void
-push_regs (mask)
-     int mask;
+push_regs (mask, mask2)
+     int mask, mask2;
 {
   int i;
 
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+  for (i = 0; i < 32; i++)
     if (mask & (1 << i))
       push (i);
+  for (i = 32; i < FIRST_PSEUDO_REGISTER; i++)
+    if (mask2 & (1 << (i - 32)))
+      push (i);
 }
 
 /* Work out the registers which need to be saved, both as a mask and a
@@ -1867,27 +1891,29 @@ push_regs (mask)
    make sure that all the regs it clobbers are safe too.  */
 
 static int
-calc_live_regs (count_ptr)
+calc_live_regs (count_ptr, live_regs_mask2)
      int *count_ptr;
+     int *live_regs_mask2;
 {
   int reg;
   int live_regs_mask = 0;
   int count = 0;
 
+  *live_regs_mask2 = 0;
   for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++)
     {
       if (pragma_interrupt && ! pragma_trapa)
        {
-         /* Normally, we must save all the regs ever live.
-            If pragma_nosave_low_regs, then don't save any of the
-            registers which are banked on the SH3.  */
+         /* Need to save all the regs ever live.  */
          if ((regs_ever_live[reg]
               || (call_used_regs[reg] && regs_ever_live[PR_REG]))
              && reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM
-             && reg != T_REG && reg != GBR_REG
-             && ! (sh_cpu == CPU_SH3 && pragma_nosave_low_regs && reg < 8))
+             && reg != T_REG && reg != GBR_REG)
            {
-             live_regs_mask |= 1 << reg;
+             if (reg >= 32)
+               *live_regs_mask2 |= 1 << (reg - 32);
+             else
+               live_regs_mask |= 1 << reg;
              count++;
            }
        }
@@ -1896,7 +1922,10 @@ calc_live_regs (count_ptr)
          /* Only push those regs which are used and need to be saved.  */
          if (regs_ever_live[reg] && ! call_used_regs[reg])
            {
-             live_regs_mask |= (1 << reg);
+             if (reg >= 32)
+               *live_regs_mask2 |= 1 << (reg - 32);
+             else
+               live_regs_mask |= (1 << reg);
              count++;
            }
        }
@@ -1913,7 +1942,8 @@ sh_expand_prologue ()
 {
   int live_regs_mask;
   int d, i;
-  live_regs_mask = calc_live_regs (&d);
+  int live_regs_mask2;
+  live_regs_mask = calc_live_regs (&d, &live_regs_mask2);
 
   /* We have pretend args if we had an object sent partially in registers
      and partially on the stack, e.g. a large structure.  */
@@ -1922,23 +1952,30 @@ sh_expand_prologue ()
   extra_push = 0;
 
   /* This is set by SETUP_VARARGS to indicate that this is a varargs
-     routine.  Clear it here so that the next function isn't affected.  */
+     routine.  Clear it here so that the next function isn't affected. */
   if (current_function_anonymous_args)
     {
       current_function_anonymous_args = 0;
 
-      /* Push arg regs as if they'd been provided by caller in stack.  */
-      for (i = 0; i < NPARM_REGS; i++)
-       {
-         int rn = NPARM_REGS + FIRST_PARM_REG - i - 1;
-         if (i > (NPARM_REGS - current_function_args_info
-                  - current_function_varargs))
-           break;
-         push (rn);
-         extra_push += 4;
-       }
+      /* This is not used by the SH3E calling convention  */
+      if (!TARGET_SH3E)
+        {
+         /* Push arg regs as if they'd been provided by caller in stack.  */
+         for (i = 0; i < NPARM_REGS(SImode); i++)
+           {
+             int rn = NPARM_REGS(SImode) + FIRST_PARM_REG - i - 1;
+             if (i > (NPARM_REGS(SImode) 
+                      - current_function_args_info.arg_count[(int) SH_ARG_INT]
+                      - current_function_varargs))
+               break;
+             push (rn);
+             extra_push += 4;
+           }
+        }
     }
-  push_regs (live_regs_mask);
+
+  push_regs (live_regs_mask, live_regs_mask2);
+
   output_stack_adjust (-get_frame_size (), stack_pointer_rtx);
 
   if (frame_pointer_needed)
@@ -1951,7 +1988,8 @@ sh_expand_epilogue ()
   int live_regs_mask;
   int d, i;
 
-  live_regs_mask = calc_live_regs (&d);
+  int live_regs_mask2;
+  live_regs_mask = calc_live_regs (&d, &live_regs_mask2);
 
   if (frame_pointer_needed)
     {
@@ -1970,7 +2008,9 @@ sh_expand_epilogue ()
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
       int j = (FIRST_PSEUDO_REGISTER - 1) - i;
-      if (live_regs_mask & (1 << j))
+      if (j < 32 && (live_regs_mask & (1 << j)))
+       pop (j);
+      else if (j >= 32 && (live_regs_mask2 & (1 << (j - 32))))
        pop (j);
     }
 
@@ -1988,6 +2028,62 @@ function_epilogue (stream, size)
   pragma_interrupt = pragma_trapa = pragma_nosave_low_regs = 0;
 }
 
+rtx
+sh_builtin_saveregs (arglist)
+     tree arglist;
+{
+  tree fntype = TREE_TYPE (current_function_decl);
+  /* First unnamed integer register.  */
+  int first_intreg = current_function_args_info.arg_count[(int) SH_ARG_INT];
+  /* Number of integer registers we need to save.  */
+  int n_intregs = MAX (0, NPARM_REGS (SImode) - first_intreg);
+  /* First unnamed SFmode float reg */
+  int first_floatreg = current_function_args_info.arg_count[(int) SH_ARG_FLOAT];
+  /* Number of SFmode float regs to save.  */
+  int n_floatregs = MAX (0, NPARM_REGS (SFmode) - first_floatreg);
+  int ptrsize = GET_MODE_SIZE (Pmode);
+  rtx valist, regbuf, fpregs;
+  int bufsize, regno;
+
+  /* Allocate block of memory for the regs. */
+  /* ??? If n_intregs + n_floatregs == 0, should we allocate at least 1 byte?
+     Or can assign_stack_local accept a 0 SIZE argument?  */
+  bufsize = (n_intregs * UNITS_PER_WORD) + (n_floatregs * UNITS_PER_WORD);
+
+  regbuf = assign_stack_local (BLKmode, bufsize, 0);
+  MEM_IN_STRUCT_P (regbuf) = 1;
+
+  /* Save int args.
+     This is optimized to only save the regs that are necessary.  Explicitly
+     named args need not be saved.  */
+  if (n_intregs > 0)
+    move_block_from_reg (BASE_ARG_REG (SImode) + first_intreg,
+                        gen_rtx (MEM, BLKmode, 
+                               plus_constant (XEXP (regbuf, 0),
+                                       n_floatregs * UNITS_PER_WORD)), 
+                        n_intregs, n_intregs * UNITS_PER_WORD);
+
+  /* Save float args.
+     This is optimized to only save the regs that are necessary.  Explicitly
+     named args need not be saved.
+     We explicitly build a pointer to the buffer because it halves the insn
+     count when not optimizing (otherwise the pointer is built for each reg
+     saved).  */
+
+  fpregs = gen_reg_rtx (Pmode);
+  emit_move_insn (fpregs, XEXP (regbuf, 0));
+  for (regno = first_floatreg; regno < NPARM_REGS (SFmode); regno ++)
+    emit_move_insn (gen_rtx (MEM, SFmode,
+                            plus_constant (fpregs,
+                                           GET_MODE_SIZE (SFmode)
+                                           * (regno - first_floatreg))),
+                   gen_rtx (REG, SFmode,
+                            BASE_ARG_REG (SFmode) + regno));
+
+  /* Return the address of the regbuf.  */
+  return XEXP (regbuf, 0);
+}
+
 /* Define the offset between two registers, one to be eliminated, and
    the other its replacement, at the start of a routine.  */
 
@@ -2000,7 +2096,9 @@ initial_elimination_offset (from, to)
   int total_saved_regs_space;
   int total_auto_space = get_frame_size ();
 
-  calc_live_regs (&regs_saved);
+  int live_regs_mask2;
+  calc_live_regs (&regs_saved, &live_regs_mask2);
+
   total_saved_regs_space = (regs_saved) * 4;
 
   if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
@@ -2138,6 +2236,7 @@ arith_reg_operand (op, mode)
       if (GET_CODE (op) == REG)
        return (REGNO (op) != T_REG
                && REGNO (op) != PR_REG
+               && REGNO (op) != FPUL_REG
                && REGNO (op) != MACH_REG
                && REGNO (op) != MACL_REG);
       return 1;
@@ -2192,60 +2291,35 @@ logical_operand (op, mode)
 
   return 0;
 }
-\f
-/* Determine where to put an argument to a function.
-   Value is zero to push the argument on the stack,
-   or a hard register in which to store the argument.
-
-   MODE is the argument's machine mode.
-   TYPE is the data type of the argument (as a tree).
-    This is null for libcalls where that information may
-    not be available.
-   CUM is a variable of type CUMULATIVE_ARGS which gives info about
-    the preceding args and about the function being called.
-   NAMED is nonzero if this argument is a named parameter
-    (otherwise it is an extra parameter matching an ellipsis).  */
 
-rtx
-sh_function_arg (cum, mode, type, named)
-     CUMULATIVE_ARGS cum;
-     enum machine_mode mode;
-     tree type;
-     int named;
+/* Nonzero if OP is a floating point value with value 0.0.  */
+
+int
+fp_zero_operand (op)
+     rtx op;
 {
-  if (named)
-    {
-      int rr = (ROUND_REG (cum, mode));
+  REAL_VALUE_TYPE r;
 
-      if (rr < NPARM_REGS)
-       return ((type == 0 || ! TREE_ADDRESSABLE (type))
-               ? gen_rtx (REG, mode, FIRST_PARM_REG + rr) : 0);
-    }
-  return 0;
+  if (GET_MODE (op) != SFmode)
+    return 0;
+
+  REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+  return REAL_VALUES_EQUAL (r, dconst0);
 }
 
-/* For an arg passed partly in registers and partly in memory,
-   this is the number of registers used.
-   For args passed entirely in registers or entirely in memory, zero.
-   Any arg that starts in the first 4 regs but won't entirely fit in them
-   needs partial registers on the SH.  */
+/* Nonzero if OP is a floating point value with value 1.0.  */
 
 int
-sh_function_arg_partial_nregs (cum, mode, type, named)
-     CUMULATIVE_ARGS cum;
-     enum machine_mode mode;
-     tree type;
-     int named;
+fp_one_operand (op)
+     rtx op;
 {
-  if (cum < NPARM_REGS)
-    {
-      if ((type == 0 || ! TREE_ADDRESSABLE (type))
-         && (cum + (mode == BLKmode
-                    ? ROUND_ADVANCE (int_size_in_bytes (type))
-                    : ROUND_ADVANCE (GET_MODE_SIZE (mode))) - NPARM_REGS > 0))
-       return NPARM_REGS - cum;
-    }
-  return 0;
+  REAL_VALUE_TYPE r;
+
+  if (GET_MODE (op) != SFmode)
+    return 0;
+
+  REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+  return REAL_VALUES_EQUAL (r, dconst1);
 }
 \f
 /* Return non-zero if REG is not used after INSN.