Starting with the 4.5.x series, we have pathological cases (Ada code generated by a code generator from a model) where FWPROP takes 80% of the compilation time at -O1 (for essentially no benefits). There are very few basic blocks (typically 1) and tens of thousands of uses registered with DF, so processing them takes a while (top function in the profile: local_ref_killed_between_p).
The attached patch is an attempt (modelled on gcse.c) at disabling the pass for these pathological cases. Thoughts? * Makefile.in (fwprop.o): Add intl.h. * fwprop.c: Include intl.h. (is_too_expensive): New function. (fwprop): Call it and return early if it returns true. (fwprop_addr): Likewise. -- Eric Botcazou
Index: Makefile.in =================================================================== --- Makefile.in (revision 183423) +++ Makefile.in (working copy) @@ -3023,9 +3023,10 @@ dse.o : dse.c $(CONFIG_H) $(SYSTEM_H) co $(TREE_PASS_H) alloc-pool.h $(ALIAS_H) dse.h $(OPTABS_H) $(TARGET_H) \ $(BITMAP_H) $(PARAMS_H) fwprop.o : fwprop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(DIAGNOSTIC_CORE_H) insn-config.h $(RECOG_H) $(FLAGS_H) $(OBSTACK_H) $(BASIC_BLOCK_H) \ - output.h $(DF_H) alloc-pool.h $(TIMEVAR_H) $(TREE_PASS_H) $(TARGET_H) \ - $(TM_P_H) $(CFGLOOP_H) $(EMIT_RTL_H) domwalk.h sparseset.h + $(DIAGNOSTIC_CORE_H) insn-config.h $(RECOG_H) $(FLAGS_H) $(OBSTACK_H) \ + intl.h $(BASIC_BLOCK_H) output.h $(DF_H) alloc-pool.h $(TIMEVAR_H) \ + $(TREE_PASS_H) $(TARGET_H) $(TM_P_H) $(CFGLOOP_H) $(EMIT_RTL_H) \ + domwalk.h sparseset.h web.o : web.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ hard-reg-set.h $(FLAGS_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h $(DIAGNOSTIC_CORE_H) \ insn-config.h $(RECOG_H) $(DF_H) $(OBSTACK_H) $(TIMEVAR_H) $(TREE_PASS_H) Index: fwprop.c =================================================================== --- fwprop.c (revision 183423) +++ fwprop.c (working copy) @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. #include "insn-config.h" #include "recog.h" #include "flags.h" +#include "intl.h" #include "obstack.h" #include "basic-block.h" #include "output.h" @@ -1435,6 +1436,28 @@ fwprop_done (void) } +/* Return true if the function is too expensive to optimize. PASS is the + optimization about to be performed. */ + +static bool +is_too_expensive (const char *pass) +{ + int ratio = DF_USES_TABLE_SIZE () / (n_basic_blocks - NUM_FIXED_BLOCKS); + + /* Trying to propagate into uses in functions with gigantic basic blocks + will take a long time and is unlikely to be particularly useful. */ + if (ratio > 20000) + { + warning (OPT_Wdisabled_optimization, + "%s: %d basic blocks and %d uses/basic block", + pass, n_basic_blocks - NUM_FIXED_BLOCKS, ratio); + + return true; + } + + return false; +} + /* Main entry point. */ static bool @@ -1451,6 +1474,12 @@ fwprop (void) fwprop_init (); + if (is_too_expensive (_("FWPROP1 disabled"))) + { + fwprop_done (); + return 0; + } + /* Go through all the uses. df_uses_create will create new ones at the end, and we'll go through them as well. @@ -1469,8 +1498,10 @@ fwprop (void) } fwprop_done (); + if (need_cleanup) cleanup_cfg (0); + return 0; } @@ -1503,6 +1534,12 @@ fwprop_addr (void) fwprop_init (); + if (is_too_expensive (_("FWPROP2 disabled"))) + { + fwprop_done (); + return 0; + } + /* Go through all the uses. df_uses_create will create new ones at the end, and we'll go through them as well. */ for (i = 0; i < DF_USES_TABLE_SIZE (); i++) @@ -1520,6 +1557,7 @@ fwprop_addr (void) if (need_cleanup) cleanup_cfg (0); + return 0; }