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;
}