OSDN Git Service

2000-12-05 Richard Sandiford <r.sandiford@redhat.com>
authorlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 6 Dec 2000 03:56:43 +0000 (03:56 +0000)
committerlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 6 Dec 2000 03:56:43 +0000 (03:56 +0000)
* config/mn10300/mn10300.c (mn10300_print_reg_list): Added.
(mn10300_get_live_callee_saved_regs): Likewise.
(mn10300_gen_multiple_store): Likewise.
(store_multiple_operation): Likewise.
(expand_prologue): Use mn10300_gen_multiple_store().
* config/mn10300/mn10300-protos.h (mn10300_print_reg_list): Added.
(mn10300_get_live_callee_saved_regs): Likewise.
(mn10300_gen_multiple_store): Likewise.
(store_multiple_operation): Likewise.
* config/mn10300/mn10300.md (store_movm): Use a MATCH_PARALLEL
tied to store_multiple_operation().

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@38062 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/mn10300/mn10300-protos.h
gcc/config/mn10300/mn10300.c
gcc/config/mn10300/mn10300.md

index bc09584..69b5ecc 100644 (file)
@@ -1,3 +1,17 @@
+2000-12-05  Richard Sandiford  <r.sandiford@redhat.com>
+
+       * config/mn10300/mn10300.c (mn10300_print_reg_list): Added.
+       (mn10300_get_live_callee_saved_regs): Likewise.
+       (mn10300_gen_multiple_store): Likewise.
+       (store_multiple_operation): Likewise.
+       (expand_prologue): Use mn10300_gen_multiple_store().
+       * config/mn10300/mn10300-protos.h (mn10300_print_reg_list): Added.
+       (mn10300_get_live_callee_saved_regs): Likewise.
+       (mn10300_gen_multiple_store): Likewise.
+       (store_multiple_operation): Likewise.
+       * config/mn10300/mn10300.md (store_movm): Use a MATCH_PARALLEL
+       tied to store_multiple_operation().
+
 Tue Dec  5 20:09:14 2000  Jeffrey A Law  (law@cygnus.com)
 
        * builtins.c (expand_builtin_setjmp_setup): Set
index 66dcbe2..ee4a443 100644 (file)
@@ -28,10 +28,14 @@ extern void mn10300_va_start PARAMS ((int, tree, rtx));
 extern struct rtx_def *legitimize_address PARAMS ((rtx, rtx, enum machine_mode));
 extern void print_operand PARAMS ((FILE *, rtx, int));
 extern void print_operand_address PARAMS ((FILE *, rtx));
+extern void mn10300_print_reg_list PARAMS ((FILE *, int));
+extern int mn10300_get_live_callee_saved_regs PARAMS ((void));
+extern void mn10300_gen_multiple_store PARAMS ((int));
 extern void notice_update_cc PARAMS ((rtx, rtx));
 extern enum reg_class secondary_reload_class PARAMS ((enum reg_class,
                                                      enum machine_mode, rtx));
 extern char *output_tst PARAMS ((rtx, rtx));
+extern int store_multiple_operation PARAMS ((rtx, enum machine_mode));
 extern int symbolic_operand PARAMS ((rtx, enum machine_mode));
 extern int call_address_operand PARAMS ((rtx, enum machine_mode));
 extern int impossible_plus_operand PARAMS ((rtx, enum machine_mode));
index 3a5454c..bc6b1fc 100644 (file)
@@ -361,6 +361,45 @@ print_operand_address (file, addr)
     }
 }
 
+/* Print a set of registers in the format required by "movm" and "ret".
+   Register K is saved if bit K of MASK is set.  The data and address
+   registers can be stored individually, but the extended registers cannot.
+   We assume that the mask alread takes that into account.  For instance,
+   bits 14 to 17 must have the same value. */
+
+void
+mn10300_print_reg_list (file, mask)
+     FILE *file;
+     int mask;
+{
+  int need_comma;
+  int i;
+
+  need_comma = 0;
+  fputc ('[', file);
+
+  for (i = 0; i < FIRST_EXTENDED_REGNUM; i++)
+    if ((mask & (1 << i)) != 0)
+      {
+       if (need_comma)
+         fputc (',', file);
+       fputs (reg_names [i], file);
+       need_comma = 1;
+      }
+
+  if ((mask & 0x3c000) != 0)
+    {
+      if ((mask & 0x3c000) != 0x3c000)
+       abort();
+      if (need_comma)
+       fputc (',', file);
+      fputs ("exreg1", file);
+      need_comma = 1;
+    }
+
+  fputc (']', file);
+}
+
 int
 can_use_return_insn ()
 {
@@ -383,6 +422,94 @@ can_use_return_insn ()
          && !frame_pointer_needed);
 }
 
+/* Returns the set of live, callee-saved registers as a bitmask.  The
+   callee-saved extended registers cannot be stored individually, so
+   all of them will be included in the mask if any one of them is used. */
+
+int
+mn10300_get_live_callee_saved_regs ()
+{
+  int mask;
+  int i;
+
+  mask = 0;
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (regs_ever_live[i] && ! call_used_regs[i])
+      mask |= (1 << i);
+  if ((mask & 0x3c000) != 0)
+    mask |= 0x3c000;
+
+  return mask;
+}
+
+/* Generate an instruction that pushes several registers onto the stack.
+   Register K will be saved if bit K in MASK is set.  The function does
+   nothing if MASK is zero.
+
+   To be compatible with the "movm" instruction, the lowest-numbered
+   register must be stored in the lowest slot.  If MASK is the set
+   { R1,...,RN }, where R1...RN are ordered least first, the generated
+   instruction will have the form:
+
+       (parallel
+         (set (reg:SI 9) (plus:SI (reg:SI 9) (const_int -N*4)))
+        (set (mem:SI (plus:SI (reg:SI 9)
+                              (const_int -1*4)))
+             (reg:SI RN))
+        ...
+        (set (mem:SI (plus:SI (reg:SI 9)
+                              (const_int -N*4)))
+             (reg:SI R1))) */
+
+void
+mn10300_gen_multiple_store (mask)
+     int mask;
+{
+  if (mask != 0)
+    {
+      int i;
+      int count;
+      rtx par;
+      int pari;
+
+      /* Count how many registers need to be saved. */
+      count = 0;
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+       if ((mask & (1 << i)) != 0)
+         count += 1;
+
+      /* We need one PARALLEL element to update the stack pointer and
+        an additional element for each register that is stored. */
+      par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 1));
+
+      /* Create the instruction that updates the stack pointer. */
+      XVECEXP (par, 0, 0)
+       = gen_rtx_SET (SImode,
+                      stack_pointer_rtx,
+                      gen_rtx_PLUS (SImode,
+                                    stack_pointer_rtx,
+                                    GEN_INT (-count * 4)));
+
+      /* Create each store. */
+      pari = 1;
+      for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
+       if ((mask & (1 << i)) != 0)
+         {
+           rtx address = gen_rtx_PLUS (SImode,
+                                       stack_pointer_rtx,
+                                       GEN_INT (-pari * 4));
+           XVECEXP(par, 0, pari)
+             = gen_rtx_SET (VOIDmode,
+                            gen_rtx_MEM (SImode, address),
+                            gen_rtx_REG (SImode, i));
+           pari += 1;
+         }
+
+      par = emit_insn (par);
+      RTX_FRAME_RELATED_P (par) = 1;
+    }
+}
+
 void
 expand_prologue ()
 {
@@ -404,14 +531,8 @@ expand_prologue ()
                      gen_rtx_REG (SImode, 1));
     }
 
-  /* And now store all the registers onto the stack with a
-     single two byte instruction.  */
-  if (regs_ever_live[2] || regs_ever_live[3]
-      || regs_ever_live[6] || regs_ever_live[7]
-      || regs_ever_live[14] || regs_ever_live[15]
-      || regs_ever_live[16] || regs_ever_live[17]
-      || frame_pointer_needed)
-    emit_insn (gen_store_movm ());
+  /* If we use any of the callee-saved registers, save them now. */
+  mn10300_gen_multiple_store (mn10300_get_live_callee_saved_regs ());
 
   /* Now put the frame pointer into the frame pointer register.  */
   if (frame_pointer_needed)
@@ -532,6 +653,87 @@ notice_update_cc (body, insn)
     }
 }
 
+/* Recognise the PARALLEL rtx generated by mn10300_gen_multiple_store().
+   This function is for MATCH_PARALLEL and so assumes OP is known to be
+   parallel.  If OP is a multiple store, return a mask indicating which
+   registers it saves.  Return 0 otherwise.  */
+
+int
+store_multiple_operation (op, mode)
+     rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  int count;
+  int mask;
+  int i;
+  unsigned int last;
+  rtx elt;
+
+  count = XVECLEN (op, 0);
+  if (count < 2)
+    return 0;
+
+  /* Check that first instruction has the form (set (sp) (plus A B)) */
+  elt = XVECEXP (op, 0, 0);
+  if (GET_CODE (elt) != SET
+      || GET_CODE (SET_DEST (elt)) != REG
+      || REGNO (SET_DEST (elt)) != STACK_POINTER_REGNUM
+      || GET_CODE (SET_SRC (elt)) != PLUS)
+    return 0;
+
+  /* Check that A is the stack pointer and B is the expected stack size.
+     For OP to match, each subsequent instruction should push a word onto
+     the stack.  We therefore expect the first instruction to create
+     COUNT-1 stack slots. */
+  elt = SET_SRC (elt);
+  if (GET_CODE (XEXP (elt, 0)) != REG
+      || REGNO (XEXP (elt, 0)) != STACK_POINTER_REGNUM
+      || GET_CODE (XEXP (elt, 1)) != CONST_INT
+      || INTVAL (XEXP (elt, 1)) != -(count - 1) * 4)
+    return 0;
+
+  /* Now go through the rest of the vector elements.  They must be
+     ordered so that the first instruction stores the highest-numbered
+     register to the highest stack slot and that subsequent instructions
+     store a lower-numbered register to the slot below.
+
+     LAST keeps track of the smallest-numbered register stored so far.
+     MASK is the set of stored registers. */
+  last = FIRST_PSEUDO_REGISTER;
+  mask = 0;
+  for (i = 1; i < count; i++)
+    {
+      /* Check that element i is a (set (mem M) R) and that R is valid. */
+      elt = XVECEXP (op, 0, i);
+      if (GET_CODE (elt) != SET
+         || GET_CODE (SET_DEST (elt)) != MEM
+         || GET_CODE (SET_SRC (elt)) != REG
+         || REGNO (SET_SRC (elt)) >= last)
+       return 0;
+
+      /* R was OK, so provisionally add it to MASK.  We return 0 in any
+        case if the rest of the instruction has a flaw. */
+      last = REGNO (SET_SRC (elt));
+      mask |= (1 << last);
+
+      /* Check that M has the form (plus (sp) (const_int -I*4)) */
+      elt = XEXP (SET_DEST (elt), 0);
+      if (GET_CODE (elt) != PLUS
+         || GET_CODE (XEXP (elt, 0)) != REG
+         || REGNO (XEXP (elt, 0)) != STACK_POINTER_REGNUM
+         || GET_CODE (XEXP (elt, 1)) != CONST_INT
+         || INTVAL (XEXP (elt, 1)) != -i * 4)
+       return 0;
+    }
+
+  /* All or none of the callee-saved extended registers must be in the set. */
+  if ((mask & 0x3c000) != 0
+      && (mask & 0x3c000) != 0x3c000)
+    return 0;
+
+  return mask;
+}
+
 /* Return true if OP is a valid call operand.  */
 
 int
index cfa9c51..564a4c9 100644 (file)
   ""
   "*
 {
-  int need_comma;
-
-  need_comma = 0;
-  fputs (\"\\tret [\", asm_out_file);
-  if (regs_ever_live[2])
-    {
-      fputs (\"d2\", asm_out_file);
-      need_comma = 1;
-    }
-  if (regs_ever_live[3])
-    {
-      if (need_comma)
-       fputc (',', asm_out_file); 
-      fputs (\"d3\", asm_out_file);
-      need_comma = 1;
-    }
-  if (regs_ever_live[6])
-    {
-      if (need_comma)
-       fputc (',', asm_out_file); 
-      fputs (\"a2\", asm_out_file);
-      need_comma = 1;
-    }
-  if (regs_ever_live[7])
-    {
-      if (need_comma)
-       fputc (',', asm_out_file); 
-      fputs (\"a3\", asm_out_file);
-      need_comma = 1;
-    }
-  if (regs_ever_live[14] || regs_ever_live[15]
-      || regs_ever_live[16] || regs_ever_live[17])
-    {
-      if (need_comma)
-       fputc (',', asm_out_file); 
-      fputs (\"exreg1\", asm_out_file);
-      need_comma = 1;
-    }
-  fprintf (asm_out_file, \"],%d\\n\", INTVAL (operands[0]));
+  fputs (\"\\tret \", asm_out_file);
+  mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs ());
+  fprintf (asm_out_file, \",%d\\n\", (int) INTVAL (operands[0]));
   return \"\";
 }"
   [(set_attr "cc" "clobber")])
 
+;; This instruction matches one generated by mn10300_gen_multiple_store()
 (define_insn "store_movm"
-  [(const_int 1)
-   (use (reg:SI 2))
-   (use (reg:SI 3))
-   (use (reg:SI 6))
-   (use (reg:SI 7))
-   (use (reg:SI 14))
-   (use (reg:SI 15))
-   (use (reg:SI 16))
-   (use (reg:SI 17))
-   (clobber (reg:SI 9))]
+  [(match_parallel 0 "store_multiple_operation"
+    [(set (reg:SI 9) (plus:SI (reg:SI 9) (match_operand 1 "" "")))])]
   ""
   "*
 {
-  int need_comma;
-
-  need_comma = 0;
-  fputs (\"\\tmovm [\", asm_out_file);
-  if (regs_ever_live[2])
-    {
-      fputs (\"d2\", asm_out_file);
-      need_comma = 1;
-    }
-  if (regs_ever_live[3])
-    {
-      if (need_comma)
-       fputc (',', asm_out_file); 
-      fputs (\"d3\", asm_out_file);
-      need_comma = 1;
-    }
-  if (regs_ever_live[6])
-    {
-      if (need_comma)
-       fputc (',', asm_out_file); 
-      fputs (\"a2\", asm_out_file);
-      need_comma = 1;
-    }
-  if (regs_ever_live[7])
-    {
-      if (need_comma)
-       fputc (',', asm_out_file); 
-      fputs (\"a3\", asm_out_file);
-      need_comma = 1;
-    }
-  if (regs_ever_live[14] || regs_ever_live[15]
-      || regs_ever_live[16] || regs_ever_live[17])
-    {
-      if (need_comma)
-       fputc (',', asm_out_file); 
-      fputs (\"exreg1\", asm_out_file);
-      need_comma = 1;
-    }
-  fputs (\"],(sp)\\n\", asm_out_file);
+  fputs (\"\\tmovm \", asm_out_file);
+  mn10300_print_reg_list (asm_out_file,
+                          store_multiple_operation (operands[0], VOIDmode));
+  fprintf (asm_out_file, \",(sp)\\n\");
   return \"\";
 }"
   [(set_attr "cc" "clobber")])
-
+  
 (define_insn "return"
   [(return)]
   "can_use_return_insn ()"