backport: Makefile.in (STAGESTUFF): Add *.peephole2.
authorRichard Henderson <rth@cygnus.com>
Tue, 31 Aug 1999 20:37:09 +0000 (13:37 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Tue, 31 Aug 1999 20:37:09 +0000 (13:37 -0700)
        Merge peephole2 from new_ia32_branch:
        * Makefile.in (STAGESTUFF): Add *.peephole2.
        (mostlyclean): Likewise.
        (recog.o): Depend on resource.h.

        * final.c (peephole): Conditionalize decl on HAVE_peephole.
        (final_scan_insn): Likewise for the invocation of peephole.
        * genconfig.c (main): Look for peephole and peephole2 patterns.
        Emit HAVE_peephole* accordingly.
        * genpeep.c (main): Conditionalize entire output on HAVE_peephole.
        * flags.h (flag_peephole2): Declare.
        * toplev.c: New pass peephole2.  New flag -fpeephole2.

        * genattrtab.c (main): Count DEFINE_PEEPHOLE2.
        * gencodes.c (main): Likewise.
        * genextract.c (main): Likewise.
        * genoutput.c (main): Likewise.
        * genemit.c (max_operand_1): Look for the max scratch operand.
        (gen_rtx_scratch): New.
        (gen_exp): Use it, and pass on new arg subroutine_type.
        (gen_expand): Take max scratch into account.
        (gen_split): Emit peephole2 functions.
        (output_peephole2_scratch): New.
        (main): Include hard-reg-set.h and resource.h.  Handle peephole2.
        * genrecog.c (routine_type): Add PEEPHOLE2.
        (IS_SPLIT): New.
        (make_insn_sequence): Match outer parallel for peep2.  Discard
        top level scratches and dups.
        (add_to_sequence): New args insn_type and top.  Update all callers.
        Handle toplevel peep2 matching insns.
        (write_subroutine): Handle peep2.
        (write_tree_1): Likewise.
        (write_tree): Likewise.
        (main): Likewise.
        (change_state): New arg afterward.  Update all callers.
        Handle matching separate insns.
        * recog.c (recog_next_insn): New.
        (peephole2_optimize): New.
        * rtl.def (DEFINE_PEEPHOLE2): New.
        * resource.c (find_free_register): New argument last_insn.  Use it
        to find a register available through the entire span.
        * resource.h (find_free_register): Update prototype.

From-SVN: r29015

18 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/final.c
gcc/flags.h
gcc/genattrtab.c
gcc/gencodes.c
gcc/genconfig.c
gcc/genemit.c
gcc/genextract.c
gcc/genoutput.c
gcc/genpeep.c
gcc/genrecog.c
gcc/recog.c
gcc/recog.h
gcc/resource.c
gcc/resource.h
gcc/rtl.def
gcc/toplev.c

index e9cac978f1ca233aec58d6eeec7f661f218e6126..c5fa34ce5cecad706c183d8e319823c68998f09d 100644 (file)
@@ -1,3 +1,48 @@
+Tue Aug 31 13:35:42 1999  Richard Henderson  <rth@cygnus.com>
+
+       Merge peephole2 from new_ia32_branch:
+       * Makefile.in (STAGESTUFF): Add *.peephole2.
+       (mostlyclean): Likewise.
+       (recog.o): Depend on resource.h.
+
+       * final.c (peephole): Conditionalize decl on HAVE_peephole.
+       (final_scan_insn): Likewise for the invocation of peephole.
+       * genconfig.c (main): Look for peephole and peephole2 patterns.
+       Emit HAVE_peephole* accordingly.
+       * genpeep.c (main): Conditionalize entire output on HAVE_peephole.
+       * flags.h (flag_peephole2): Declare.
+       * toplev.c: New pass peephole2.  New flag -fpeephole2.
+       * genattrtab.c (main): Count DEFINE_PEEPHOLE2.
+       * gencodes.c (main): Likewise.
+       * genextract.c (main): Likewise.
+       * genoutput.c (main): Likewise.
+       * genemit.c (max_operand_1): Look for the max scratch operand.
+       (gen_rtx_scratch): New.
+       (gen_exp): Use it, and pass on new arg subroutine_type.
+       (gen_expand): Take max scratch into account.
+       (gen_split): Emit peephole2 functions.
+       (output_peephole2_scratch): New.
+       (main): Include hard-reg-set.h and resource.h.  Handle peephole2.
+       * genrecog.c (routine_type): Add PEEPHOLE2.
+       (IS_SPLIT): New.
+       (make_insn_sequence): Match outer parallel for peep2.  Discard
+       top level scratches and dups.
+       (add_to_sequence): New args insn_type and top.  Update all callers.
+       Handle toplevel peep2 matching insns.
+       (write_subroutine): Handle peep2.
+       (write_tree_1): Likewise.
+       (write_tree): Likewise.
+       (main): Likewise.
+       (change_state): New arg afterward.  Update all callers.
+       Handle matching separate insns.
+       * recog.c (recog_next_insn): New.
+       (peephole2_optimize): New.
+       * rtl.def (DEFINE_PEEPHOLE2): New.
+       * resource.c (find_free_register): New argument last_insn.  Use it
+       to find a register available through the entire span.
+       * resource.h (find_free_register): Update prototype.
+
 Tue Aug 31 11:51:06 1999  Jim Kingdon  <http://developer.redhat.com>
 
        * i386.c (output_strlen_unroll): Don't write xops[7]
index 92b285371c28bdeb409d819293cc0bfc57af68f3..445a46b230fa28232e0f20862d6c3694aa80e7b5 100644 (file)
@@ -697,7 +697,7 @@ STAGESTUFF = *$(objext) insn-flags.h insn-config.h insn-codes.h \
  specs collect2$(exeext) $(USE_COLLECT2) underscore.c \
  gcov$(exeext) *.bp \
  *.greg *.lreg *.combine *.flow *.cse *.jump *.rtl *.tree *.loop \
- *.dbr *.jump2 *.sched *.cse2 *.sched2 *.stack *.gcse *.flow2 \
+ *.dbr *.jump2 *.sched *.cse2 *.sched2 *.stack *.gcse *.flow2 *.peephole2 \
  *.[si] libcpp.a \
  $(LANG_STAGESTUFF)
 
@@ -1577,10 +1577,10 @@ final.o : final.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h intl.h \
    dbxout.h
 recog.o : recog.c $(CONFIG_H) system.h $(RTL_H) function.h \
    $(REGS_H) $(RECOG_H) hard-reg-set.h flags.h insn-config.h insn-attr.h \
-   insn-flags.h insn-codes.h real.h toplev.h
+   insn-flags.h insn-codes.h real.h toplev.h output.h resource.h
 reg-stack.o : reg-stack.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) recog.h \
    $(REGS_H) hard-reg-set.h flags.h insn-config.h insn-flags.h toplev.h \
-   function.h
+   varray.h function.h
 dyn-string.o: dyn-string.c dyn-string.h $(CONFIG_H) system.h
 lists.o: lists.c $(CONFIG_H) system.h toplev.h $(RTL_H)
 
@@ -2311,10 +2311,11 @@ mostlyclean: intl.mostlyclean lang.mostlyclean
 # Delete debugging dump files.
        -rm -f *.greg *.lreg *.combine *.flow *.cse *.jump *.rtl *.tree *.loop
        -rm -f *.dbr *.jump2 *.sched *.cse2 *.sched2 *.stack *.addressof
-       -rm -f *.regmove *.mach *.bp *.gcse *.flow2
+       -rm -f *.regmove *.mach *.bp *.gcse *.flow2 *.peephole2
        -rm -f */*.greg */*.lreg */*.combine */*.flow */*.cse */*.jump */*.rtl
        -rm -f */*.tree */*.loop */*.dbr */*.jump2 */*.sched */*.cse2
        -rm -f */*.sched2 */*.stack */*.regmove */*.gcse */*.flow2
+       -rm -f */*.peephole2
 # Delete some files made during installation.
        -rm -f specs float.h-* enquire SYSCALLS.c.X SYSCALLS.c
        -rm -f collect collect2 mips-tfile mips-tdump alloca.s
index c4d470820461eb67591a62e2b2d42c08b7effc00..4134ae3e407c1a8147c936c1b32f7bb8744b26aa 100644 (file)
@@ -284,7 +284,9 @@ struct bb_str {
   int length;                  /* string length */
 };
 
+#ifdef HAVE_peephole
 extern rtx peephole            PROTO((rtx));
+#endif
 
 static struct bb_str *sbb_head = 0;            /* Head of string list.  */
 static struct bb_str **sbb_tail        = &sbb_head;    /* Ptr to store next bb str */
@@ -2825,6 +2827,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
 
 #endif
 
+#ifdef HAVE_peephole
        /* Do machine-specific peephole optimizations if desired.  */
 
        if (optimize && !flag_no_peephole && !nopeepholes)
@@ -2855,6 +2858,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
            /* PEEPHOLE might have changed this.  */
            body = PATTERN (insn);
          }
+#endif
 
        /* Try to recognize the instruction.
           If successful, verify that the operands satisfy the
index c81a721833a7e1d3e30eb239333b724134150161..cbdf9cde151e62ee19b7e897caf62e12492e8918 100644 (file)
@@ -473,6 +473,9 @@ extern int flag_regmove;
 
 /* Instrument functions with calls at entry and exit, for profiling.  */
 extern int flag_instrument_function_entry_exit;
+
+/* Perform a peephole pass before sched2. */
+extern int flag_peephole2;
 \f
 /* Other basic status info about current function.  */
 
index 9fb0bf0d6d2c313ca66be1d140fa0fe19700915b..a958025cb2bb5a165206248d314b3bef850ef99b 100644 (file)
@@ -6018,6 +6018,9 @@ from the machine description file `md'.  */\n\n");
       else if (GET_CODE (desc) == DEFINE_SPLIT)
        insn_code_number++, insn_index_number++;
 
+      else if (GET_CODE (desc) == DEFINE_PEEPHOLE2)
+       insn_code_number++, insn_index_number++;
+
       else if (GET_CODE (desc) == DEFINE_ATTR)
        {
          gen_attr (desc);
index c737e2a6d30fc5514bc3d8dc1f40558721598d49..084cfa80d50f744aade426a2906f758602729103 100644 (file)
@@ -125,6 +125,7 @@ from the machine description file `md'.  */\n\n");
          insn_code_number++;
        }
       if (GET_CODE (desc) == DEFINE_PEEPHOLE
+         || GET_CODE (desc) == DEFINE_PEEPHOLE2
          || GET_CODE (desc) == DEFINE_SPLIT)
        {
          insn_code_number++;
index 8f4568d37ad13d311e3914c9e9f630d6bff3b461..4001774eba3b7d5d8a0bcbf088896e4f991d7815 100644 (file)
@@ -43,6 +43,8 @@ static int register_constraint_flag;
 static int have_cc0_flag;
 static int have_cmove_flag;
 static int have_lo_sum_flag;
+static int have_peephole_flag;
+static int have_peephole2_flag;
 
 /* Maximum number of insns seen in a split.  */
 static int max_insns_per_split = 1;
@@ -313,8 +315,16 @@ from the machine description file `md'.  */\n\n");
        gen_expand (desc);
       if (GET_CODE (desc) == DEFINE_SPLIT)
        gen_split (desc);
+      if (GET_CODE (desc) == DEFINE_PEEPHOLE2)
+       {
+         have_peephole2_flag = 1;
+         gen_split (desc);
+       }
       if (GET_CODE (desc) == DEFINE_PEEPHOLE)
-       gen_peephole (desc);
+       {
+         have_peephole_flag = 1;
+         gen_peephole (desc);
+       }
     }
 
   printf ("\n#define MAX_RECOG_OPERANDS %d\n", max_recog_operands + 1);
@@ -338,6 +348,12 @@ from the machine description file `md'.  */\n\n");
   if (have_lo_sum_flag)
     printf ("#define HAVE_lo_sum\n");
 
+  if (have_peephole_flag)
+    printf ("#define HAVE_peephole\n");
+
+  if (have_peephole2_flag)
+    printf ("#define HAVE_peephole2\n");
+
   fflush (stdout);
   exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
   /* NOTREACHED */
index dc9a49af9d6f56f384aad3c7a00e6f730582cb15..68188e6c2ea96b94701043de8a64a9520e61ed4a 100644 (file)
@@ -36,6 +36,7 @@ char **insn_name_ptr = 0;
 
 static int max_opno;
 static int max_dup_opno;
+static int max_scratch_opno;
 static int register_constraints;
 static int insn_code_number;
 static int insn_index_number;
@@ -63,12 +64,13 @@ struct clobber_ent
 static void max_operand_1              PROTO((rtx));
 static int max_operand_vec             PROTO((rtx, int));
 static void print_code                 PROTO((RTX_CODE));
-static void gen_exp                    PROTO((rtx));
+static void gen_exp                    PROTO((rtx, enum rtx_code));
 static void gen_insn                   PROTO((rtx));
 static void gen_expand                 PROTO((rtx));
 static void gen_split                  PROTO((rtx));
 static void output_add_clobbers                PROTO((void));
-static void output_init_mov_optab      PROTO((void));
+static void gen_rtx_scratch            PROTO((rtx, enum rtx_code));
+static void output_peephole2_scratches PROTO((rtx));
 
 \f
 static void
@@ -94,6 +96,8 @@ max_operand_1 (x)
     max_opno = MAX (max_opno, XINT (x, 0));
   if (code == MATCH_DUP || code == MATCH_OP_DUP || code == MATCH_PAR_DUP)
     max_dup_opno = MAX (max_dup_opno, XINT (x, 0));
+  if (code == MATCH_SCRATCH)
+    max_scratch_opno = MAX (max_scratch_opno, XINT (x, 0));
 
   fmt = GET_RTX_FORMAT (code);
   len = GET_RTX_LENGTH (code);
@@ -120,6 +124,7 @@ max_operand_vec (insn, arg)
 
   max_opno = -1;
   max_dup_opno = -1;
+  max_scratch_opno = -1;
 
   for (i = 0; i < len; i++)
     max_operand_1 (XVECEXP (insn, arg, i));
@@ -141,12 +146,28 @@ print_code (code)
     }
 }
 
+static void
+gen_rtx_scratch (x, subroutine_type)
+     rtx x;
+     enum rtx_code subroutine_type;
+{
+  if (subroutine_type == DEFINE_PEEPHOLE2)
+    {
+      printf ("operand%d", XINT (x, 0));
+    }
+  else
+    {
+      printf ("gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x)));
+    }
+}
+
 /* Print a C expression to construct an RTX just like X,
    substituting any operand references appearing within.  */
 
 static void
-gen_exp (x)
+gen_exp (x, subroutine_type)
      rtx x;
+     enum rtx_code subroutine_type;
 {
   register RTX_CODE code;
   register int i;
@@ -177,7 +198,7 @@ gen_exp (x)
       for (i = 0; i < XVECLEN (x, 1); i++)
        {
          printf (",\n\t\t");
-         gen_exp (XVECEXP (x, 1, i));
+         gen_exp (XVECEXP (x, 1, i), subroutine_type);
        }
       printf (")");
       return;
@@ -188,7 +209,7 @@ gen_exp (x)
       for (i = 0; i < XVECLEN (x, 2); i++)
        {
          printf (",\n\t\t");
-         gen_exp (XVECEXP (x, 2, i));
+         gen_exp (XVECEXP (x, 2, i), subroutine_type);
        }
       printf (")");
       return;
@@ -199,7 +220,7 @@ gen_exp (x)
       return;
 
     case MATCH_SCRATCH:
-      printf ("gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x)));
+      gen_rtx_scratch (x, subroutine_type);
       return;
 
     case ADDRESS:
@@ -251,7 +272,7 @@ gen_exp (x)
        break;
       printf (",\n\t");
       if (fmt[i] == 'e' || fmt[i] == 'u')
-       gen_exp (XEXP (x, i));
+       gen_exp (XEXP (x, i), subroutine_type);
       else if (fmt[i] == 'i')
        printf ("%u", XINT (x, i));
       else if (fmt[i] == 's')
@@ -263,7 +284,7 @@ gen_exp (x)
          for (j = 0; j < XVECLEN (x, i); j++)
            {
              printf (",\n\t\t");
-             gen_exp (XVECEXP (x, i, j));
+             gen_exp (XVECEXP (x, i, j), subroutine_type);
            }
          printf (")");
        }
@@ -375,7 +396,7 @@ gen_insn (insn)
   if (XVECLEN (insn, 1) == 1)
     {
       printf ("  return ");
-      gen_exp (XVECEXP (insn, 1, 0));
+      gen_exp (XVECEXP (insn, 1, 0), DEFINE_INSN);
       printf (";\n}\n\n");
     }
   else
@@ -384,7 +405,7 @@ gen_insn (insn)
       for (i = 0; i < XVECLEN (insn, 1); i++)
        {
          printf (",\n\t\t");
-         gen_exp (XVECEXP (insn, 1, i));
+         gen_exp (XVECEXP (insn, 1, i), DEFINE_INSN);
        }
       printf ("));\n}\n\n");
     }
@@ -427,7 +448,7 @@ gen_expand (expand)
       && XVECLEN (expand, 1) == 1)
     {
       printf ("  return ");
-      gen_exp (XVECEXP (expand, 1, 0));
+      gen_exp (XVECEXP (expand, 1, 0), DEFINE_EXPAND);
       printf (";\n}\n\n");
       return;
     }
@@ -436,8 +457,11 @@ gen_expand (expand)
      make a local variable.  */
   for (i = operands; i <= max_dup_opno; i++)
     printf ("  rtx operand%d;\n", i);
-  if (operands > 0 || max_dup_opno >= 0)
-    printf ("  rtx operands[%d];\n", MAX (operands, max_dup_opno + 1));
+  for (; i <= max_scratch_opno; i++)
+    printf ("  rtx operand%d;\n", i);
+  if (operands > 0 || max_dup_opno >= 0 || max_scratch_opno >= 0)
+    printf ("  rtx operands[%d];\n",
+           MAX (operands, MAX (max_scratch_opno, max_dup_opno) + 1));
   printf ("  rtx _val = 0;\n");
   printf ("  start_sequence ();\n");
 
@@ -465,6 +489,8 @@ gen_expand (expand)
            printf ("  operand%d = operands[%d];\n", i, i);
          for (; i <= max_dup_opno; i++)
            printf ("  operand%d = operands[%d];\n", i, i);
+         for (; i <= max_scratch_opno; i++)
+           printf ("  operand%d = operands[%d];\n", i, i);
        }
     }
 
@@ -501,7 +527,7 @@ gen_expand (expand)
        printf ("  emit (");
       else
        printf ("  emit_insn (");
-      gen_exp (next);
+      gen_exp (next, DEFINE_EXPAND);
       printf (");\n");
       if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC
          && GET_CODE (SET_SRC (next)) == LABEL_REF)
@@ -524,28 +550,49 @@ gen_split (split)
 {
   register int i;
   int operands;
+  char *name = "split";
+
+  if (GET_CODE (split) == DEFINE_PEEPHOLE2)
+    name = "peephole2";
 
   if (XVEC (split, 0) == 0)
-    fatal ("define_split (definition %d) lacks a pattern", insn_index_number);
+    fatal ("define_%s (definition %d) lacks a pattern", name,
+          insn_index_number);
   else if (XVEC (split, 2) == 0)
-    fatal ("define_split (definition %d) lacks a replacement pattern",
+    fatal ("define_%s (definition %d) lacks a replacement pattern", name,
           insn_index_number);
 
   /* Find out how many operands this function has.  */
 
   max_operand_vec (split, 2);
-  operands = MAX (max_opno, max_dup_opno) + 1;
+  operands = MAX (max_opno, MAX (max_dup_opno, max_scratch_opno)) + 1;
 
-  /* Output the prototype, the function name and argument declarations.  */
-  printf ("extern rtx gen_split_%d PROTO ((rtx *));\n", insn_code_number);
-  printf ("rtx\ngen_split_%d (operands)\n     rtx *operands;\n",
-         insn_code_number);
+  /* Output the prototype, function name and argument declarations.  */
+  if (GET_CODE (split) == DEFINE_PEEPHOLE2)
+    {
+      printf ("extern rtx gen_%s_%d PROTO ((rtx, rtx *));\n",
+             name, insn_code_number);
+      printf ("rtx\ngen_%s_%d (curr_insn, operands)\n\
+     rtx curr_insn ATTRIBUTE_UNUSED;\n\
+     rtx *operands;\n", 
+             name, insn_code_number);
+    }
+  else
+    {
+      printf ("extern rtx gen_split_%d PROTO ((rtx *));\n", insn_code_number);
+      printf ("rtx\ngen_%s_%d (operands)\n     rtx *operands;\n", name,
+             insn_code_number);
+    }
   printf ("{\n");
 
   /* Declare all local variables.  */
   for (i = 0; i < operands; i++)
     printf ("  rtx operand%d;\n", i);
   printf ("  rtx _val = 0;\n");
+
+  if (GET_CODE (split) == DEFINE_PEEPHOLE2)
+    output_peephole2_scratches (split);
+
   printf ("  start_sequence ();\n");
 
   /* The fourth operand of DEFINE_SPLIT is some code to be executed
@@ -590,7 +637,7 @@ gen_split (split)
        printf ("  emit (");
       else
        printf ("  emit_insn (");
-      gen_exp (next);
+      gen_exp (next, GET_CODE (split));
       printf (");\n");
       if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC
          && GET_CODE (SET_SRC (next)) == LABEL_REF)
@@ -630,7 +677,8 @@ output_add_clobbers ()
       for (i = clobber->first_clobber; i < XVECLEN (clobber->pattern, 1); i++)
        {
          printf ("      XVECEXP (pattern, 0, %d) = ", i);
-         gen_exp (XVECEXP (clobber->pattern, 1, i));
+         gen_exp (XVECEXP (clobber->pattern, 1, i),
+                  GET_CODE (clobber->pattern));
          printf (";\n");
        }
 
@@ -643,6 +691,56 @@ output_add_clobbers ()
   printf ("}\n");
 }
 \f
+/* Generate code to invoke find_free_register () as needed for the
+   scratch registers used by the peephole2 pattern in SPLIT. */
+
+static void
+output_peephole2_scratches (split)
+     rtx split;
+{
+  int i;
+  int insn_nr = 0;
+
+  printf ("  rtx first_insn ATTRIBUTE_UNUSED;\n");
+  printf ("  rtx last_insn ATTRIBUTE_UNUSED;\n");
+  printf ("  HARD_REG_SET _regs_allocated;\n");
+
+  printf ("  CLEAR_HARD_REG_SET (_regs_allocated);\n");
+
+  for (i = 0; i < XVECLEN (split, 0); i++)
+    {
+      rtx elt = XVECEXP (split, 0, i);
+      if (GET_CODE (elt) == MATCH_SCRATCH)
+       {
+         int last_insn_nr = insn_nr;
+         int cur_insn_nr = insn_nr;
+         int j;
+         for (j = i + 1; j < XVECLEN (split, 0); j++)
+           if (GET_CODE (XVECEXP (split, 0, j)) == MATCH_DUP)
+             {
+               if (XINT (XVECEXP (split, 0, j), 0) == XINT (elt, 0))
+                 last_insn_nr = cur_insn_nr;
+             }
+           else if (GET_CODE (XVECEXP (split, 0, j)) != MATCH_SCRATCH)
+             cur_insn_nr++;
+         printf ("  first_insn = recog_next_insn (curr_insn, %d);\n", insn_nr);
+         if (last_insn_nr > insn_nr)
+           printf ("  last_insn = recog_next_insn (curr_insn, %d);\n",
+                   last_insn_nr - 1);
+         else
+           printf ("  last_insn = 0;\n");
+         printf ("  if ((operands[%d] = find_free_register (first_insn, last_insn, \"%s\", %smode, &_regs_allocated)) == NULL_RTX)\n\
+    return NULL;\n", 
+                 XINT (elt, 0),
+                 XSTR (elt, 1),
+                 GET_MODE_NAME (GET_MODE (elt)));
+
+       }
+      else if (GET_CODE (elt) != MATCH_DUP)
+       insn_nr++;
+    }
+}
+\f
 PTR
 xmalloc (size)
   size_t size;
@@ -713,6 +811,8 @@ from the machine description file `md'.  */\n\n");
   printf ("#include \"insn-flags.h\"\n");
   printf ("#include \"insn-codes.h\"\n");
   printf ("#include \"recog.h\"\n");
+  printf ("#include \"hard-reg-set.h\"\n");
+  printf ("#include \"resource.h\"\n");
   printf ("#include \"reload.h\"\n\n");
   printf ("extern rtx recog_operand[];\n");
   printf ("#define operands emit_operand\n\n");
@@ -729,6 +829,7 @@ from the machine description file `md'.  */\n\n");
       ungetc (c, infile);
 
       desc = read_rtx (infile);
+
       if (GET_CODE (desc) == DEFINE_INSN)
        {
          gen_insn (desc);
@@ -744,6 +845,11 @@ from the machine description file `md'.  */\n\n");
          gen_split (desc);
          ++insn_code_number;
        }
+      if (GET_CODE (desc) == DEFINE_PEEPHOLE2)
+       {
+         gen_split (desc);
+         ++insn_code_number;
+       }
       if (GET_CODE (desc) == DEFINE_PEEPHOLE)
        {
          ++insn_code_number;
index d3b2061ba4ec8e06653c9e69bfad83648c7d8f6b..7caec63ae841dd5a36c51aef3f652b27820fc4a7 100644 (file)
@@ -463,6 +463,7 @@ from the machine description file `md'.  */\n\n");
        }
 
       else if (GET_CODE (desc) == DEFINE_EXPAND
+              || GET_CODE (desc) == DEFINE_PEEPHOLE2
               || GET_CODE (desc) == DEFINE_SPLIT)
        ++insn_code_number;
     }
index c0a4cf581634474780cfd88f620c0510cf8a6ee4..abe0b77367f429498a26937c9b330a8e15bad881 100644 (file)
@@ -968,7 +968,8 @@ main (argc, argv)
        gen_peephole (desc);
       if (GET_CODE (desc) == DEFINE_EXPAND)
        gen_expand (desc);
-      if (GET_CODE (desc) == DEFINE_SPLIT)
+      if (GET_CODE (desc) == DEFINE_SPLIT
+         || GET_CODE (desc) == DEFINE_PEEPHOLE2)
        gen_split (desc);
       next_index_number++;
     }
index 3a877fe6cc0e3d0655f9eecc0afb5d1036d46a9e..0e6b0dbb1f88680a0b5d589904d04af6b67a8459 100644 (file)
@@ -445,6 +445,7 @@ from the machine description file `md'.  */\n\n");
   printf ("#include \"except.h\"\n\n");
   printf ("#include \"function.h\"\n\n");
 
+  printf ("#ifdef HAVE_peephole\n");
   printf ("extern rtx peep_operand[];\n\n");
   printf ("#define operands peep_operand\n\n");
 
@@ -485,6 +486,7 @@ from the machine description file `md'.  */\n\n");
     max_opno = 1;
 
   printf ("rtx peep_operand[%d];\n", max_opno + 1);
+  printf ("#endif\n");
 
   fflush (stdout);
   exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
index 166fc7a0e256ac17f8ad533d82ef858414251392..a2eef4617d81b88951a296f2167686c70a9dc6af 100644 (file)
@@ -111,10 +111,13 @@ struct decision
 
 static int next_subroutine_number;
 
-/* We can write two types of subroutines: One for insn recognition and
-   one to split insns.  This defines which type is being written.  */
+/* We can write three types of subroutines: One for insn recognition,
+   one to split insns, and one for peephole-type optimizations.  This
+   defines which type is being written.  */
 
-enum routine_type {RECOG, SPLIT};
+enum routine_type {RECOG, SPLIT, PEEPHOLE2};
+
+#define IS_SPLIT(X) ((X) == SPLIT || (X)==PEEPHOLE2)
 
 /* Next available node number for tree nodes.  */
 
@@ -173,7 +176,8 @@ static struct pred_table
 
 static struct decision_head make_insn_sequence PROTO((rtx, enum routine_type));
 static struct decision *add_to_sequence PROTO((rtx, struct decision_head *,
-                                              const char *));
+                                              const char *, 
+                                              enum routine_type, int));
 static int not_both_true       PROTO((struct decision *, struct decision *,
                                       int));
 static int position_merit      PROTO((struct decision *, enum machine_mode,
@@ -193,8 +197,9 @@ static void clear_modes             PROTO((struct decision *));
 static void write_tree         PROTO((struct decision *, const char *,
                                       struct decision *, int,
                                       enum routine_type));
-static void change_state       PROTO((const char *, const char *, int));
-
+static void change_state       PROTO((const char *, const char *, int,
+                                      struct decision *));
+\f
 /* Construct and return a sequence of decisions
    that will recognize INSN.
 
@@ -219,9 +224,8 @@ make_insn_sequence (insn, type)
       {
        int new_size;
        new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
-       insn_name_ptr =
-         (char **) xrealloc (insn_name_ptr, sizeof(char *) * new_size);
-       bzero ((PTR)(insn_name_ptr + insn_name_ptr_size),
+       insn_name_ptr = xrealloc (insn_name_ptr, sizeof(char *) * new_size);
+       bzero (insn_name_ptr + insn_name_ptr_size,
               sizeof(char *) * (new_size - insn_name_ptr_size));
        insn_name_ptr_size = new_size;
       }
@@ -243,7 +247,29 @@ make_insn_sequence (insn, type)
     insn_name_ptr[next_insn_code] = name;
   }  
 
-  if (XVECLEN (insn, type == RECOG) == 1)
+  if (type == PEEPHOLE2)
+    {
+      int i, j;
+
+      /* peephole2 gets special treatment:
+        - X always gets an outer parallel even if it's only one entry
+        - we remove all traces of outer-level match_scratch and match_dup
+           expressions here.  */
+      x = rtx_alloc (PARALLEL);
+      PUT_MODE (x, VOIDmode);
+      XVEC (x, 0) = rtvec_alloc (XVECLEN (insn, 0));
+      for (i = j = 0; i < XVECLEN (insn, 0); i++)
+       {
+         rtx tmp = XVECEXP (insn, 0, i);
+         if (GET_CODE (tmp) != MATCH_SCRATCH && GET_CODE (tmp) != MATCH_DUP)
+           {
+             XVECEXP (x, 0, j) = tmp;
+             j++;
+           }
+       }
+      XVECLEN (x, 0) = j;
+    }
+  else if (XVECLEN (insn, type == RECOG) == 1)
     x = XVECEXP (insn, type == RECOG, 0);
   else
     {
@@ -252,7 +278,7 @@ make_insn_sequence (insn, type)
       PUT_MODE (x, VOIDmode);
     }
 
-  last = add_to_sequence (x, &head, "");
+  last = add_to_sequence (x, &head, "", type, 1);
 
   if (c_test[0])
     last->c_test = c_test;
@@ -290,7 +316,7 @@ make_insn_sequence (insn, type)
                XVECEXP (new, 0, j) = XVECEXP (x, 0, j);
            }
 
-         last = add_to_sequence (new, &clobber_head, "");
+         last = add_to_sequence (new, &clobber_head, "", type, 1);
 
          if (c_test[0])
            last->c_test = c_test;
@@ -305,7 +331,13 @@ make_insn_sequence (insn, type)
 
   if (type == SPLIT)
     /* Define the subroutine we will call below and emit in genemit.  */
-    printf ("extern rtx gen_split_%d PROTO ((rtx *));\n", last->insn_code_number);
+    printf ("extern rtx gen_split_%d PROTO ((rtx *));\n",
+           last->insn_code_number);
+
+  else if (type == PEEPHOLE2)
+    /* Define the subroutine we will call below and emit in genemit.  */
+    printf ("extern rtx gen_peephole2_%d PROTO ((rtx, rtx *));\n",
+           last->insn_code_number);
 
   return head;
 }
@@ -318,13 +350,17 @@ make_insn_sequence (insn, type)
 
    POSITION is the string representing the current position in the insn.
 
+   INSN_TYPE is the type of insn for which we are emitting code.
+
    A pointer to the final node in the chain is returned.  */
 
 static struct decision *
-add_to_sequence (pattern, last, position)
+add_to_sequence (pattern, last, position, insn_type, top)
      rtx pattern;
      struct decision_head *last;
      const char *position;
+     enum routine_type insn_type;
+     int top;
 {
   register RTX_CODE code;
   register struct decision *new
@@ -381,6 +417,27 @@ add_to_sequence (pattern, last, position)
 
   switch (code)
     {
+    case PARALLEL:
+      /* Toplevel peephole pattern. */
+      if (insn_type == PEEPHOLE2 && top)
+       {
+         struct decision_head *place = last;
+
+         for (i = 0; i < (size_t) XVECLEN (pattern, 0); i++)
+           {
+             /* Which insn we're looking at is represented by A-Z. We don't
+                ever use 'A', however; it is always implied. */
+             if (i > 0)
+               newpos[depth] = 'A' + i;
+             else
+               newpos[depth] = 0;
+             new = add_to_sequence (XVECEXP (pattern, 0, i),
+                                    place, newpos, insn_type, 0);
+             place = &new->success;
+           }
+         return new;
+       }
+      break;
     case MATCH_OPERAND:
     case MATCH_SCRATCH:
     case MATCH_OPERATOR:
@@ -452,7 +509,7 @@ add_to_sequence (pattern, last, position)
            {
              newpos[depth] = i + (code == MATCH_OPERATOR ? '0': 'a');
              new = add_to_sequence (XVECEXP (pattern, 2, i),
-                                    &new->success, newpos);
+                                    &new->success, newpos, insn_type, 0);
            }
        }
 
@@ -467,7 +524,7 @@ add_to_sequence (pattern, last, position)
        {
          newpos[depth] = i + '0';
          new = add_to_sequence (XVECEXP (pattern, 1, i),
-                                &new->success, newpos);
+                                &new->success, newpos, insn_type, 0);
        }
       return new;
 
@@ -497,10 +554,12 @@ add_to_sequence (pattern, last, position)
          fatal ("mode mismatch in SET");
        }
       newpos[depth] = '0';
-      new = add_to_sequence (SET_DEST (pattern), &new->success, newpos);
+      new = add_to_sequence (SET_DEST (pattern), &new->success, newpos, 
+                            insn_type, 0);
       this->success.first->enforce_mode = 1;
       newpos[depth] = '1';
-      new = add_to_sequence (SET_SRC (pattern), &new->success, newpos);
+      new = add_to_sequence (SET_SRC (pattern), &new->success, newpos,
+                            insn_type, 0);
 
       /* If set are setting CC0 from anything other than a COMPARE, we
         must enforce the mode so that we do not produce ambiguous insns.  */
@@ -513,7 +572,8 @@ add_to_sequence (pattern, last, position)
     case ZERO_EXTEND:
     case STRICT_LOW_PART:
       newpos[depth] = '0';
-      new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos);
+      new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos, 
+                            insn_type, 0);
       this->success.first->enforce_mode = 1;
       return new;
 
@@ -521,19 +581,23 @@ add_to_sequence (pattern, last, position)
       this->test_elt_one_int = 1;
       this->elt_one_int = XINT (pattern, 1);
       newpos[depth] = '0';
-      new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos);
+      new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos,
+                            insn_type, 0);
       this->success.first->enforce_mode = 1;
       return new;
 
     case ZERO_EXTRACT:
     case SIGN_EXTRACT:
       newpos[depth] = '0';
-      new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos);
+      new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos,
+                            insn_type, 0);
       this->success.first->enforce_mode = 1;
       newpos[depth] = '1';
-      new = add_to_sequence (XEXP (pattern, 1), &new->success, newpos);
+      new = add_to_sequence (XEXP (pattern, 1), &new->success, newpos,
+                            insn_type, 0);
       newpos[depth] = '2';
-      new = add_to_sequence (XEXP (pattern, 2), &new->success, newpos);
+      new = add_to_sequence (XEXP (pattern, 2), &new->success, newpos,
+                            insn_type, 0);
       return new;
 
     case EQ:   case NE:   case LE:   case LT:   case GE:  case GT:
@@ -548,10 +612,12 @@ add_to_sequence (pattern, last, position)
     case COMPARE:
       /* Enforce the mode on the first operand to avoid ambiguous insns.  */
       newpos[depth] = '0';
-      new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos);
+      new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos,
+                            insn_type, 0);
       this->success.first->enforce_mode = 1;
       newpos[depth] = '1';
-      new = add_to_sequence (XEXP (pattern, 1), &new->success, newpos);
+      new = add_to_sequence (XEXP (pattern, 1), &new->success, newpos,
+                            insn_type, 0);
       return new;
       
     default:
@@ -564,7 +630,8 @@ add_to_sequence (pattern, last, position)
     {
       newpos[depth] = '0' + i;
       if (fmt[i] == 'e' || fmt[i] == 'u')
-       new = add_to_sequence (XEXP (pattern, i), &new->success, newpos);
+       new = add_to_sequence (XEXP (pattern, i), &new->success, newpos,
+                              insn_type, 0);
       else if (fmt[i] == 'i' && i == 0)
        {
          this->test_elt_zero_int = 1;
@@ -596,7 +663,7 @@ add_to_sequence (pattern, last, position)
            {
              newpos[depth] = 'a' + j;
              new = add_to_sequence (XVECEXP (pattern, i, j),
-                                    &new->success, newpos);
+                                    &new->success, newpos, insn_type, 0);
            }
        }
       else if (fmt[i] != '0')
@@ -1030,7 +1097,9 @@ write_subroutine (tree, type)
 {
   int i;
 
-  if (type == SPLIT)
+  if (type == PEEPHOLE2)
+    printf ("extern rtx peephole2");
+  else if (type == SPLIT)
     printf ("extern rtx split");
   else
     printf ("extern int recog");
@@ -1041,26 +1110,36 @@ write_subroutine (tree, type)
   printf (" PROTO ((rtx, rtx");
   if (type == RECOG)
     printf (", int *");
+  else if (type == PEEPHOLE2)
+    printf (", rtx *");
   printf ("));\n");
 
-  if (type == SPLIT)
+  if (type == PEEPHOLE2)
+    printf ("rtx\npeephole2");
+  else if (type == SPLIT)
     printf ("rtx\nsplit");
   else
     printf ("int\nrecog");
 
   if (tree != 0 && tree->subroutine_number > 0)
     printf ("_%d", tree->subroutine_number);
-  else if (type == SPLIT)
+  else if (IS_SPLIT (type))
     printf ("_insns");
 
   printf (" (x0, insn");
   if (type == RECOG)
     printf (", pnum_clobbers");
+  else if (type == PEEPHOLE2)
+    printf (", _plast_insn");
 
   printf (")\n");
+  /* The peephole2 pass uses the insn argument to determine which
+     hard registers are available at that point. */
   printf ("     register rtx x0;\n     rtx insn ATTRIBUTE_UNUSED;\n");
   if (type == RECOG)
     printf ("     int *pnum_clobbers ATTRIBUTE_UNUSED;\n");
+  else if (type == PEEPHOLE2)
+    printf ("     rtx *_plast_insn ATTRIBUTE_UNUSED;\n");
 
   printf ("{\n");
   printf ("  register rtx *ro = &recog_operand[0];\n");
@@ -1070,9 +1149,13 @@ write_subroutine (tree, type)
     printf ("x%d ATTRIBUTE_UNUSED, ", i);
 
   printf ("x%d ATTRIBUTE_UNUSED;\n", max_depth);
-  printf ("  %s tem ATTRIBUTE_UNUSED;\n", type == SPLIT ? "rtx" : "int");
+  if (type == PEEPHOLE2)
+    printf ("  register rtx _last_insn = insn;\n");
+  printf ("  %s tem ATTRIBUTE_UNUSED;\n", IS_SPLIT (type) ? "rtx" : "int");
   write_tree (tree, "", NULL_PTR, 1, type);
-  printf (" ret0: return %d;\n}\n\n", type == SPLIT ? 0 : -1);
+  if (type == PEEPHOLE2)
+    printf (" ret1:\n  *_plast_insn = _last_insn;\n  return tem;\n");
+  printf (" ret0:\n  return %d;\n}\n\n", IS_SPLIT (type) ? 0 : -1);
 }
 \f
 /* This table is used to indent the recog_* functions when we are inside
@@ -1157,7 +1240,7 @@ write_tree_1 (tree, prevpos, afterward, type)
 
   if (tree)
     {
-      change_state (prevpos, tree->position, 2);
+      change_state (prevpos, tree->position, 2, afterward);
       prevpos = tree->position;
     }
 
@@ -1308,7 +1391,8 @@ write_tree_1 (tree, prevpos, afterward, type)
              if (afterward)
                {
                  printf ("    {\n");
-                 change_state (p->position, afterward->position, 6);
+                 change_state (p->position, afterward->position, 6,
+                               afterward);
                  printf ("      goto L%d;\n    }\n", afterward->number);
                }
              else
@@ -1328,7 +1412,8 @@ write_tree_1 (tree, prevpos, afterward, type)
              if (afterward)
                {
                  printf ("    {\n");
-                 change_state (p->position, afterward->position, indent + 4);
+                 change_state (p->position, afterward->position, indent + 4,
+                               afterward);
                  printf ("    goto L%d;\n    }\n", afterward->number);
                }
              else
@@ -1466,9 +1551,22 @@ write_tree_1 (tree, prevpos, afterward, type)
       if (p->insn_code_number >= 0)
        {
          if (type == SPLIT)
-           printf ("%sreturn gen_split_%d (operands);\n",
-                   indents[inner_indent], p->insn_code_number);
-         else
+           {
+             printf ("%sreturn gen_split_%d (operands);\n",
+                     indents[inner_indent], p->insn_code_number);
+           }
+         else if (type == PEEPHOLE2)
+           {
+             printf ("%s{\n", indents[inner_indent]);
+             inner_indent += 2;
+
+             printf ("%stem = gen_peephole2_%d (insn, operands);\n",
+                     indents[inner_indent], p->insn_code_number);
+             printf ("%sif (tem != 0) goto ret1;\n", indents[inner_indent]);
+             inner_indent -= 2;
+             printf ("%s}\n", indents[inner_indent]);
+           }
+         else      
            {
              if (p->num_clobbers_to_add)
                {
@@ -1528,7 +1626,7 @@ write_tree_1 (tree, prevpos, afterward, type)
 
   if (afterward)
     {
-      change_state (prevpos, afterward->position, 2);
+      change_state (prevpos, afterward->position, 2, afterward);
       printf ("  goto L%d;\n", afterward->number);
     }
   else
@@ -1606,9 +1704,24 @@ write_tree (tree, prevpos, afterward, initial, type)
      enum routine_type type;
 {
   register struct decision *p;
-  const char *name_prefix = (type == SPLIT ? "split" : "recog");
-  const char *call_suffix = (type == SPLIT ? "" : ", pnum_clobbers");
+  const char *name_prefix;
+  const char *call_suffix;
 
+  switch (type)
+    {
+    case SPLIT:
+      name_prefix = "split";
+      call_suffix = "";
+      break;
+    case PEEPHOLE2:
+      name_prefix = "peephole2";
+      call_suffix = ", _plast_insn";
+      break;
+    case RECOG:
+      name_prefix = "recog";
+      call_suffix = ", pnum_clobbers";
+      break;
+    }
   if (! initial && tree->subroutine_number > 0)
     {
       OUTPUT_LABEL (" ", tree->number);
@@ -1617,11 +1730,11 @@ write_tree (tree, prevpos, afterward, initial, type)
        {
          printf ("  tem = %s_%d (x0, insn%s);\n",
                  name_prefix, tree->subroutine_number, call_suffix);
-         if (type == SPLIT)
+         if (IS_SPLIT (type))
            printf ("  if (tem != 0) return tem;\n");
          else
            printf ("  if (tem >= 0) return tem;\n");
-         change_state (tree->position, afterward->position, 2);
+         change_state (tree->position, afterward->position, 2, afterward);
          printf ("  goto L%d;\n", afterward->number);
        }
       else
@@ -1640,30 +1753,76 @@ write_tree (tree, prevpos, afterward, initial, type)
 
 \f
 /* Assuming that the state of argument is denoted by OLDPOS, take whatever
-   actions are necessary to move to NEWPOS.
+   actions are necessary to move to NEWPOS. If we fail to move to the
+   new state, branch to node AFTERWARD if non-zero, otherwise return.
+
+   INDENT says how many blanks to place at the front of lines.  
 
-   INDENT says how many blanks to place at the front of lines.  */
+   Failure to move to the new state can only occur if we are trying to
+   match multiple insns and we try to step past the end of the
+   stream. */
 
 static void
-change_state (oldpos, newpos, indent)
+change_state (oldpos, newpos, indent, afterward)
      const char *oldpos;
      const char *newpos;
      int indent;
+     struct decision *afterward;
 {
   int odepth = strlen (oldpos);
   int depth = odepth;
   int ndepth = strlen (newpos);
+  int basedepth;
+  int old_has_insn, new_has_insn;
 
   /* Pop up as many levels as necessary.  */
 
   while (strncmp (oldpos, newpos, depth))
     --depth;
+  basedepth = depth;
+
+  /* Make sure to reset the _last_insn pointer when popping back up.  */
+  for (old_has_insn = odepth - 1; old_has_insn >= 0; --old_has_insn)
+    if (oldpos[old_has_insn] >= 'A' && oldpos[old_has_insn] <= 'Z')
+      break;
+  for (new_has_insn = odepth - 1; new_has_insn >= 0; --new_has_insn)
+    if (newpos[new_has_insn] >= 'A' && newpos[new_has_insn] <= 'Z')
+      break;
+
+  if (old_has_insn >= 0 && new_has_insn < 0)
+    printf ("%s_last_insn = insn;\n", indents[indent]);
 
   /* Go down to desired level.  */
 
   while (depth < ndepth)
     {
-      if (newpos[depth] >= 'a' && newpos[depth] <= 'z')
+      /* It's a different insn from the first one. */
+      if (newpos[depth] >= 'A' && newpos[depth] <= 'Z')
+       {
+         /* We can only fail if we're moving down the tree.  */
+         if (old_has_insn >= 0 && oldpos[old_has_insn] >= newpos[depth])
+           {
+             printf ("%s_last_insn = recog_next_insn (insn, %d);\n", 
+                     indents[indent], newpos[depth] - 'A');
+           }
+         else
+           {
+             printf ("%stem = recog_next_insn (insn, %d);\n", 
+                     indents[indent], newpos[depth] - 'A');
+
+             printf ("%sif (tem == NULL_RTX)\n", indents[indent]);
+             if (afterward)
+               printf ("%sgoto L%d;\n", indents[indent + 2],
+                       afterward->number);
+             else
+               printf ("%sgoto ret0;\n", indents[indent + 2]);
+
+             printf ("%s_last_insn = tem;\n", indents[indent]);
+           }
+         printf ("%sx%d = PATTERN (_last_insn);\n",
+                 indents[indent], depth + 1);
+       }
+      else if (newpos[depth] >= 'a' && newpos[depth] <= 'z')
        printf ("%sx%d = XVECEXP (x%d, 0, %d);\n",
                indents[indent], depth + 1, depth, newpos[depth] - 'a');
       else
@@ -1717,12 +1876,14 @@ main (argc, argv)
   rtx desc;
   struct decision_head recog_tree;
   struct decision_head split_tree;
+  struct decision_head peephole2_tree;
   FILE *infile;
   register int c;
 
   progname = "genrecog";
   obstack_init (rtl_obstack);
   recog_tree.first = recog_tree.last = split_tree.first = split_tree.last = 0;
+  peephole2_tree.first = peephole2_tree.last = 0;
 
   if (argc <= 1)
     fatal ("No input file name.");
@@ -1767,6 +1928,10 @@ from the machine description file `md'.  */\n\n");
       else if (GET_CODE (desc) == DEFINE_SPLIT)
        split_tree = merge_trees (split_tree,
                                  make_insn_sequence (desc, SPLIT));
+      else if (GET_CODE (desc) == DEFINE_PEEPHOLE2)
+       peephole2_tree = merge_trees (peephole2_tree,
+                                     make_insn_sequence (desc, PEEPHOLE2));
+       
       if (GET_CODE (desc) == DEFINE_PEEPHOLE
          || GET_CODE (desc) == DEFINE_EXPAND)
        next_insn_code++;
@@ -1797,6 +1962,11 @@ from the machine description file `md'.  */\n\n");
     printf ("\n\n   The function split_insns returns 0 if the rtl could not\n\
    be split or the split rtl in a SEQUENCE if it can be.");
 
+  if (peephole2_tree.first)
+    printf ("\n\n   The function peephole2_insns returns 0 if the rtl could not\n\
+   be matched. If there was a match, the new rtl is returned in a SEQUENCE,\n\
+   and LAST_INSN will point to the last recognized insn in the old sequence.");
+
   printf ("*/\n\n");
 
   printf ("#define operands recog_operand\n\n");
@@ -1809,6 +1979,10 @@ from the machine description file `md'.  */\n\n");
   break_out_subroutines (split_tree, SPLIT, 1);
   write_subroutine (split_tree.first, SPLIT);
 
+  next_subroutine_number = 0;
+  break_out_subroutines (peephole2_tree, PEEPHOLE2, 1);
+  write_subroutine (peephole2_tree.first, PEEPHOLE2);
+
   fflush (stdout);
   exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
   /* NOTREACHED */
index f41c3d1895956069440f0e63e520d513b6ccca1f..95c93d4dcc9307ccf448720513715aa38530b9fb 100644 (file)
@@ -34,6 +34,8 @@ Boston, MA 02111-1307, USA.  */
 #include "real.h"
 #include "toplev.h"
 #include "basic-block.h"
+#include "output.h"
+#include "resource.h"
 
 #ifndef STACK_PUSH_CODE
 #ifdef STACK_GROWS_DOWNWARD
@@ -2688,3 +2690,69 @@ split_block_insns (b, do_split)
        break;
     }
 }
+\f
+#ifdef HAVE_peephole2
+/* Return the Nth non-note insn after INSN, or return NULL_RTX if it does
+   not exist.  Used by the recognizer to find the next insn to match in a
+   multi-insn pattern.  */
+rtx
+recog_next_insn (insn, n)
+     rtx insn;
+     int n;
+{
+  while (insn != NULL_RTX && n > 0)
+    {
+      insn = next_nonnote_insn (insn);
+
+      if (insn == NULL_RTX)
+       return insn;
+
+      if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+       return NULL_RTX;
+
+      n--;
+    }
+
+  return insn;
+}
+
+/* Perform the peephole2 optimization pass. */
+void
+peephole2_optimize (dump_file)
+     FILE *dump_file ATTRIBUTE_UNUSED;
+{
+  rtx insn;
+  rtx epilogue_insn = 0;
+
+  for (insn = get_last_insn (); insn != NULL_RTX; insn = PREV_INSN (insn))
+    {
+      if (GET_CODE (insn) == NOTE
+         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
+       {
+         epilogue_insn = insn;
+         break;
+       }
+    }
+
+  init_resource_info (epilogue_insn);
+
+  for (insn = get_insns (); insn != NULL;
+       insn = next_nonnote_insn (insn))
+    {
+      if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
+       {
+         rtx last_insn;
+         rtx before = PREV_INSN (insn);
+
+         rtx try = peephole2_insns (PATTERN (insn), insn, &last_insn);
+         if (try != NULL)
+           {
+             replace_insns (insn, last_insn, try, NULL_RTX);
+             insn = NEXT_INSN (before);
+           }
+       }
+    }
+
+  free_resource_info ();
+}
+#endif
index c8a6598cb4aba32238262180bc68efff4c7a7009..0337214e76d99496ecc8337528d9a520a4f3aecf 100644 (file)
@@ -114,6 +114,9 @@ extern void add_clobbers            PROTO((rtx, int));
 extern void insn_extract               PROTO((rtx));
 extern void extract_insn               PROTO((rtx));
 extern void preprocess_constraints     PROTO((void));
+extern rtx recog_next_insn             PROTO((rtx, int));
+extern void peephole2_optimize         PROTO((FILE *));
+extern rtx peephole2_insns             PROTO((rtx, rtx, rtx *));
 
 /* Nonzero means volatile operands are recognized.  */
 extern int volatile_ok;
index daa839c54a71669737076b1c72483720c3bd9a76..880264594f7947f51884da34a6e17cb2ae233f1e 100644 (file)
@@ -1239,17 +1239,20 @@ mark_end_of_function_resources (trial, include_delayed_effects)
                             include_delayed_effects);
 }
 \f
-/* Try to find an available hard register of mode MODE at
-   CURRENT_INSN, matching the register class in CLASS_STR. Registers
-   that already have bits set in REG_SET will not be considered.
+/* Try to find a hard register of mode MODE, matching the register class in
+   CLASS_STR, which is available at the beginning of insn CURRENT_INSN and
+   remains available until the end of LAST_INSN.  LAST_INSN may be NULL_RTX,
+   in which case the only condition is that the register must be available
+   before CURRENT_INSN.
+   Registers that already have bits set in REG_SET will not be considered.
 
    If an appropriate register is available, it will be returned and the
    corresponding bit(s) in REG_SET will be set; otherwise, NULL_RTX is
    returned.  */
 
 rtx
-find_free_register (current_insn, class_str, mode, reg_set)
-     rtx current_insn;
+find_free_register (current_insn, last_insn, class_str, mode, reg_set)
+     rtx current_insn, last_insn;
      char *class_str;
      int mode;
      HARD_REG_SET *reg_set;
@@ -1261,6 +1264,14 @@ find_free_register (current_insn, class_str, mode, reg_set)
     = (clet == 'r' ? GENERAL_REGS :  REG_CLASS_FROM_LETTER (clet));
 
   mark_target_live_regs (get_insns (), current_insn, &used);
+  if (last_insn)
+    while (current_insn != last_insn)
+      {
+       /* Exclude anything set in this insn.  */
+       mark_set_resources (PATTERN (current_insn), &used, 0, 1);
+       current_insn = next_nonnote_insn (current_insn);
+      }
+
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
index d3a8e2c7088716cbde2e8b159280c9bf3dc7e58e..49f3c4ff343196159489bea33b9eb538ccc35955 100644 (file)
@@ -42,5 +42,5 @@ extern void incr_ticks_for_insn               PROTO((rtx));
 extern void mark_end_of_function_resources PROTO ((rtx, int));
 extern void init_resource_info         PROTO((rtx));
 extern void free_resource_info         PROTO((void));
-extern rtx find_free_register          PROTO((rtx, char *, int,
+extern rtx find_free_register          PROTO((rtx, rtx, char *, int,
                                               HARD_REG_SET *));
index 357585e37f92123e86e27b547f6691c84971a711..0b5a83a85e809dd339a6eb7e39bf69bf120c74f8 100644 (file)
@@ -207,6 +207,10 @@ DEF_RTL_EXPR(DEFINE_PEEPHOLE, "define_peephole", "EssV", 'x')
        (`operands' is an alias here for `recog_operand').   */
 DEF_RTL_EXPR(DEFINE_SPLIT, "define_split", "EsES", 'x')
 
+/* Definition of an RTL peephole operation.
+   Follows the same arguments as define_split.  */
+DEF_RTL_EXPR(DEFINE_PEEPHOLE2, "define_peephole2", "EsES", 'x')
+
 /* Definition of a combiner pattern.
    Operands not defined yet.  */
 DEF_RTL_EXPR(DEFINE_COMBINE, "define_combine", "Ess", 'x')
index 532c98b1f74b01586c45dc420b5d9cd8fa1da6e1..a3017b70d3aea77d015242f2509108621eeb37a1 100644 (file)
@@ -290,6 +290,7 @@ int sched_dump = 0;
 int local_reg_dump = 0;
 int global_reg_dump = 0;
 int flow2_dump = 0;
+int peephole2_dump = 0;
 int sched2_dump = 0;
 int jump2_opt_dump = 0;
 #ifdef DELAY_SLOTS
@@ -761,6 +762,9 @@ int flag_instrument_function_entry_exit = 0;
 
 int flag_no_ident = 0;
 
+/* This will perform a peephole pass before sched2. */
+int flag_peephole2 = 0;
+
 /* Table of supported debugging formats.  */
 static struct
 {
@@ -966,7 +970,9 @@ lang_independent_options f_options[] =
   {"leading-underscore", &flag_leading_underscore, 1,
    "External symbols have a leading underscore" },
   {"ident", &flag_no_ident, 0,
-   "Process #ident directives"}
+   "Process #ident directives"},
+  { "peephole2", &flag_peephole2, 1,
+    "Enables an rtl peephole pass run before sched2" }
 };
 
 #define NUM_ELEM(a)  (sizeof (a) / sizeof ((a)[0]))
@@ -3004,6 +3010,12 @@ compile_file (name)
       if (graph_dump_format != no_graph)
        clean_graph_dump_file (dump_base_name, ".flow2");
     }
+  if (peephole2_dump)
+    {
+      clean_dump_file (".peephole2");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".peephole2");
+    }
   if (sched2_dump)
     {
       clean_dump_file (".sched2");
@@ -4226,6 +4238,23 @@ rest_of_compilation (decl)
        print_rtl_graph_with_bb (dump_base_name, ".flow2", insns);
     }
 
+#ifdef HAVE_peephole2
+  if (optimize > 0 && flag_peephole2)
+    {
+      if (peephole2_dump)
+       open_dump_file (".peephole2", decl_printable_name (decl, 2));
+
+      peephole2_optimize (rtl_dump_file);
+
+      if (peephole2_dump)
+       {
+         close_dump_file (print_rtl_with_bb, insns);
+         if (graph_dump_format != no_graph)
+           print_rtl_graph_with_bb (dump_base_name, ".peephole2", insns);
+       }
+    }
+#endif
+
   if (optimize > 0 && flag_schedule_insns_after_reload)
     {
       if (sched2_dump)
@@ -4822,6 +4851,7 @@ main (argc, argv)
       flag_rerun_loop_opt = 1;
       flag_caller_saves = 1;
       flag_force_mem = 1;
+      flag_peephole2 = 1;
 #ifdef INSN_SCHEDULING
       flag_schedule_insns = 1;
       flag_schedule_insns_after_reload = 1;
@@ -4917,6 +4947,7 @@ main (argc, argv)
 #ifdef MACHINE_DEPENDENT_REORG
                    mach_dep_reorg_dump = 1;
 #endif
+                   peephole2_dump = 1;
                    break;
                  case 'A':
                    flag_debug_asm = 1;
@@ -4996,11 +5027,14 @@ main (argc, argv)
                  case 'w':
                    flow2_dump = 1;
                    break;
+                 case 'x':
+                   rtl_dump_and_exit = 1;
+                   break;
                  case 'y':
                    set_yydebug (1);
                    break;
-                 case 'x':
-                   rtl_dump_and_exit = 1;
+                 case 'z':
+                   peephole2_dump = 1;
                    break;
                  case 'D':     /* these are handled by the preprocessor */
                  case 'I':