aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@cygnus.com>1999-08-31 13:37:09 -0700
committerRichard Henderson <rth@gcc.gnu.org>1999-08-31 13:37:09 -0700
commitede7cd44999a94c3eeb6708db37d6939045b554e (patch)
treeafdcdc35501714ae0479a8139d1ee32d313b0176
parent4dfeccf9d064821bede6f09da2949499f19c68c4 (diff)
downloadgcc-ede7cd44999a94c3eeb6708db37d6939045b554e.zip
gcc-ede7cd44999a94c3eeb6708db37d6939045b554e.tar.gz
gcc-ede7cd44999a94c3eeb6708db37d6939045b554e.tar.bz2
backport: Makefile.in (STAGESTUFF): Add *.peephole2.
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
-rw-r--r--gcc/ChangeLog45
-rw-r--r--gcc/Makefile.in9
-rw-r--r--gcc/final.c4
-rw-r--r--gcc/flags.h3
-rw-r--r--gcc/genattrtab.c3
-rw-r--r--gcc/gencodes.c1
-rw-r--r--gcc/genconfig.c18
-rw-r--r--gcc/genemit.c152
-rw-r--r--gcc/genextract.c1
-rw-r--r--gcc/genoutput.c3
-rw-r--r--gcc/genpeep.c2
-rw-r--r--gcc/genrecog.c268
-rw-r--r--gcc/recog.c68
-rw-r--r--gcc/recog.h3
-rw-r--r--gcc/resource.c21
-rw-r--r--gcc/resource.h2
-rw-r--r--gcc/rtl.def4
-rw-r--r--gcc/toplev.c40
18 files changed, 562 insertions, 85 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e9cac97..c5fa34c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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]
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 92b2853..445a46b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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
diff --git a/gcc/final.c b/gcc/final.c
index c4d4708..4134ae3 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -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
diff --git a/gcc/flags.h b/gcc/flags.h
index c81a721..cbdf9cd 100644
--- a/gcc/flags.h
+++ b/gcc/flags.h
@@ -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;
/* Other basic status info about current function. */
diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c
index 9fb0bf0..a958025 100644
--- a/gcc/genattrtab.c
+++ b/gcc/genattrtab.c
@@ -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);
diff --git a/gcc/gencodes.c b/gcc/gencodes.c
index c737e2a..084cfa8 100644
--- a/gcc/gencodes.c
+++ b/gcc/gencodes.c
@@ -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++;
diff --git a/gcc/genconfig.c b/gcc/genconfig.c
index 8f4568d..4001774 100644
--- a/gcc/genconfig.c
+++ b/gcc/genconfig.c
@@ -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 */
diff --git a/gcc/genemit.c b/gcc/genemit.c
index dc9a49a..68188e6 100644
--- a/gcc/genemit.c
+++ b/gcc/genemit.c
@@ -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));
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");
}
+/* 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++;
+ }
+}
+
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;
diff --git a/gcc/genextract.c b/gcc/genextract.c
index d3b2061..7caec63 100644
--- a/gcc/genextract.c
+++ b/gcc/genextract.c
@@ -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;
}
diff --git a/gcc/genoutput.c b/gcc/genoutput.c
index c0a4cf5..abe0b77 100644
--- a/gcc/genoutput.c
+++ b/gcc/genoutput.c
@@ -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++;
}
diff --git a/gcc/genpeep.c b/gcc/genpeep.c
index 3a877fe..0e6b0db 100644
--- a/gcc/genpeep.c
+++ b/gcc/genpeep.c
@@ -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);
diff --git a/gcc/genrecog.c b/gcc/genrecog.c
index 166fc7a..a2eef46 100644
--- a/gcc/genrecog.c
+++ b/gcc/genrecog.c
@@ -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 *));
+
/* 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);
}
/* 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)
/* 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 */
diff --git a/gcc/recog.c b/gcc/recog.c
index f41c3d1..95c93d4 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -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;
}
}
+
+#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
diff --git a/gcc/recog.h b/gcc/recog.h
index c8a6598..0337214 100644
--- a/gcc/recog.h
+++ b/gcc/recog.h
@@ -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;
diff --git a/gcc/resource.c b/gcc/resource.c
index daa839c..8802645 100644
--- a/gcc/resource.c
+++ b/gcc/resource.c
@@ -1239,17 +1239,20 @@ mark_end_of_function_resources (trial, include_delayed_effects)
include_delayed_effects);
}
-/* 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++)
{
diff --git a/gcc/resource.h b/gcc/resource.h
index d3a8e2c..49f3c4f 100644
--- a/gcc/resource.h
+++ b/gcc/resource.h
@@ -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 *));
diff --git a/gcc/rtl.def b/gcc/rtl.def
index 357585e..0b5a83a 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -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')
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 532c98b..a3017b7 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -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':