Where there can be multiple things wrong with a pattern sequence, performance-wise, and multiple things might be fixed up, depending on factors like available registers, providing patterns for every combination leads to combinatorial explosion. It is simpler to describe the available transformations in simpler steps that can be chained. However, the peephole2 pass currently makes only a single pass over a basic block. With the attached patch, a peephole2 pattern can set a new variable, peep2_rescan, to request that the current basic block is re-scanned. Bootstrapped and regtested on i686-pc-linux-gnu.
I've been using this mechanism for the Epiphany port to transform add instructions generated by reload or later passes, which require expensive flag register save/restore operations, and often have an unnecessary constant load, into variants which are cheaper.
2011-10-30 Joern Rennecke <joern.renne...@embecosm.com> * recog.c (peep2_rescan): New variable. (peephole2_optimize): Clear peep2_rescan at the start of each block. Loop if peep2_rescan is set at the end of processing a block. * recog.h (peep2_rescan): Declare. * doc/md.texi: Document peep2_rescan. Index: doc/md.texi =================================================================== --- doc/md.texi (revision 180683) +++ doc/md.texi (working copy) @@ -6872,6 +6872,20 @@ If we had not added the @code{(match_dup sequence, it might have been the case that the register we chose at the beginning of the sequence is killed by the first or second @code{set}. +The @code{peephole2} pass usually scans each basic block only once. If you +have a @code{peephole2} pattern that, once applied, might enable other +@code{peephole2} patterns to be matched, you can request to re-run the +scan over the current basic block by setting the variable +@code{peep2_rescan} to @code{true} in the @var{preparation-statements} +of the @code{peephole2} pattern. +You should be careful not to create infinite loops by doing this. +E.g. one technique to avoid loops is to have a cost function (as a concept +to describe the pattern sequences, not necessarily actual code - although +for complex designs, implementing it as actual code might help debugging + and/or implementation), and make sure that any @code{peephole2} pattern +that sets @code{peep2_rescan} lowers this cost function, and no +@code{peephole2} pattern increases this cost function. + @end ifset @ifset INTERNALS @node Insn Attributes Index: recog.c =================================================================== --- recog.c (revision 180683) +++ recog.c (working copy) @@ -1,6 +1,6 @@ /* Subroutines used by or related to instruction recognition. Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. This file is part of GCC. @@ -3467,6 +3467,8 @@ peep2_fill_buffer (basic_block bb, rtx i return true; } +bool peep2_rescan; + /* Perform the peephole2 optimization pass. */ static void @@ -3491,9 +3493,14 @@ peephole2_optimize (void) FOR_EACH_BB_REVERSE (bb) { - bool past_end = false; + bool past_end; int pos; + rescan_block: + peep2_rescan = false; + + past_end = false; + rtl_profile_for_bb (bb); /* Start up propagation. */ @@ -3546,6 +3553,8 @@ peephole2_optimize (void) peep2_current = peep2_buf_position (peep2_current + 1); peep2_current_count--; } + if (peep2_rescan) + goto rescan_block; } default_rtl_profile (); Index: recog.h =================================================================== --- recog.h (revision 180683) +++ recog.h (working copy) @@ -1,6 +1,6 @@ /* Declarations for interface to insn recognizer and insn-output.c. Copyright (C) 1987, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, - 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. This file is part of GCC. @@ -311,5 +311,6 @@ struct insn_data_d extern const struct insn_data_d insn_data[]; extern int peep2_current_count; +extern bool peep2_rescan; #endif /* GCC_RECOG_H */