diff options
author | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-08-31 20:37:09 +0000 |
---|---|---|
committer | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-08-31 20:37:09 +0000 |
commit | 82575fa702c5782ac79aad4b5d7c86b597bc71b0 (patch) | |
tree | afdcdc35501714ae0479a8139d1ee32d313b0176 /gcc | |
parent | be342bf0a6c4d5aae61aa50960e164e7a49e206a (diff) | |
download | gcc-82575fa702c5782ac79aad4b5d7c86b597bc71b0.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@29015 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 45 | ||||
-rw-r--r-- | gcc/Makefile.in | 9 | ||||
-rw-r--r-- | gcc/final.c | 4 | ||||
-rw-r--r-- | gcc/flags.h | 3 | ||||
-rw-r--r-- | gcc/genattrtab.c | 3 | ||||
-rw-r--r-- | gcc/gencodes.c | 1 | ||||
-rw-r--r-- | gcc/genconfig.c | 18 | ||||
-rw-r--r-- | gcc/genemit.c | 152 | ||||
-rw-r--r-- | gcc/genextract.c | 1 | ||||
-rw-r--r-- | gcc/genoutput.c | 3 | ||||
-rw-r--r-- | gcc/genpeep.c | 2 | ||||
-rw-r--r-- | gcc/genrecog.c | 268 | ||||
-rw-r--r-- | gcc/recog.c | 68 | ||||
-rw-r--r-- | gcc/recog.h | 3 | ||||
-rw-r--r-- | gcc/resource.c | 21 | ||||
-rw-r--r-- | gcc/resource.h | 2 | ||||
-rw-r--r-- | gcc/rtl.def | 4 | ||||
-rw-r--r-- | gcc/toplev.c | 40 |
18 files changed, 562 insertions, 85 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e9cac978f1c..c5fa34ce5ce 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 92b285371c2..445a46b230f 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 c4d47082046..4134ae3e407 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 c81a721833a..cbdf9cde151 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 9fb0bf0d6d2..a958025cb2b 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 c737e2a6d30..084cfa80d50 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 8f4568d37ad..4001774eba3 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 dc9a49af9d6..68188e6c2ea 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 d3b2061ba4e..7caec63ae84 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 c0a4cf58163..abe0b77367f 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 3a877fe6cc0..0e6b0dbb1f8 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 166fc7a0e25..a2eef4617d8 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 f41c3d18959..95c93d4dcc9 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 c8a6598cb4a..0337214e76d 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 daa839c54a7..880264594f7 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 d3a8e2c7088..49f3c4ff343 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 357585e37f9..0b5a83a85e8 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 532c98b1f74..a3017b70d3a 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': |