This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Speed up genattrtab
On Wed, Jun 16, 2010 at 04:33:34PM +0200, Jakub Jelinek wrote:
> On Tue, Jun 15, 2010 at 09:16:33PM +0200, Jakub Jelinek wrote:
> > On Tue, Jun 15, 2010 at 11:39:47AM -0700, Mark Mitchell wrote:
> > I believe on x86_64/i686 the most time is spent in compiling
> > internal_dfa_insn_code, primarily because there are so many different
> > schedulings.
> > The insn is a big switch on recog_memoized, where most of the cases first
> > compare ix86_schedule var to some enum. I guess it would be certainly
> > faster to compile to instead split the big function into separate function
> > for each schedule and make internal_dfa_insn_code a function pointer, would
> > need to be benchmarked how it would actually perform at runtime.
>
> Here is a WIP untested patch.
And here is a patch I've actually bootstrapped/regtested on x86_64-linux and
i686-linux. It was an --enable-checking=release build (simultaneously both
arches), so timing wasn't exact, but config.status timestamp to compare
timestamp difference was
1112s -> 843s x86_64
736s -> 630s i686.
Times from config.status to end of make were
2453s -> 2111s x86_64
1190s -> 1100s i686
and times from config.status to and of make check were
4033s -> 3805s x86_64
3331s -> 3303s i686
Except for a few expected differences (insn-attrtab.o, files including
insn-attr.h and *checksum* gcc/*.o had no differences on stripped objects).
2010-06-16 Jakub Jelinek <jakub@redhat.com>
* Makefile.in (cfgexpand.o): Depend on $(INSN_ATTR_H).
* genattrtab.c (check_tune_attr, find_tune_attr): New functions.
(make_automaton_attrs): If find_tune_attr returns non-NULL,
write separate internal_dfa_insn_code_* and insn_default_latency_*
functions for each attribute's value and emit init_sched_attrs
function and function pointers.
* genattr.c (const_attrs, reservations): New variables.
(gen_attr): Add const attributes to const_attrs vector.
(check_tune_attr, find_tune_attr): New functions.
(main): Add reservations to reservations vector. If find_tune_attr
returns true, add prototype for init_sched_attrs and make
internal_dfa_insn_code and insn_default_latency function pointers,
otherwise define init_sched_attrs as dummy macro.
* cfgexpand.c: Include insn-attr.h.
(gimple_expand_cfg): Call init_sched_attrs.
--- gcc/Makefile.in.jj 2010-06-15 10:37:06.000000000 +0200
+++ gcc/Makefile.in 2010-06-16 18:41:41.000000000 +0200
@@ -3192,7 +3192,7 @@ cfgexpand.o : cfgexpand.c $(TREE_FLOW_H)
coretypes.h $(TREE_DUMP_H) $(EXCEPT_H) langhooks.h $(TREE_PASS_H) $(RTL_H) \
$(DIAGNOSTIC_H) $(TOPLEV_H) $(BASIC_BLOCK_H) $(FLAGS_H) debug.h $(PARAMS_H) \
value-prof.h $(TREE_INLINE_H) $(TARGET_H) $(SSAEXPAND_H) \
- tree-pretty-print.h gimple-pretty-print.h $(BITMAP_H) sbitmap.h
+ tree-pretty-print.h gimple-pretty-print.h $(BITMAP_H) sbitmap.h $(INSN_ATTR_H)
cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(FLAGS_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h \
output.h $(TOPLEV_H) $(FUNCTION_H) $(EXCEPT_H) $(TM_P_H) $(INSN_ATTR_H) \
--- gcc/genattrtab.c.jj 2010-06-11 09:38:08.000000000 +0200
+++ gcc/genattrtab.c 2010-06-16 19:19:57.000000000 +0200
@@ -1,6 +1,6 @@
/* Generate code from machine description to compute values of attributes.
Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
@@ -4372,6 +4372,69 @@ process_bypasses (void)
r->bypassed = true;
}
+/* Check that attribute NAME is used in define_insn_reservation condition
+ EXP. Return true if it is. */
+static bool
+check_tune_attr (const char *name, rtx exp)
+{
+ switch (GET_CODE (exp))
+ {
+ case AND:
+ if (check_tune_attr (name, XEXP (exp, 0)))
+ return true;
+ return check_tune_attr (name, XEXP (exp, 1));
+
+ case IOR:
+ return (check_tune_attr (name, XEXP (exp, 0))
+ && check_tune_attr (name, XEXP (exp, 1)));
+
+ case EQ_ATTR:
+ return XSTR (exp, 0) == name;
+
+ default:
+ return false;
+ }
+}
+
+/* Try to find a const attribute (usually cpu or tune) that is used
+ in all define_insn_reservation conditions. */
+static struct attr_desc *
+find_tune_attr (rtx exp)
+{
+ struct attr_desc *attr;
+
+ switch (GET_CODE (exp))
+ {
+ case AND:
+ case IOR:
+ attr = find_tune_attr (XEXP (exp, 0));
+ if (attr)
+ return attr;
+ return find_tune_attr (XEXP (exp, 1));
+
+ case EQ_ATTR:
+ if (XSTR (exp, 0) == alternative_name)
+ return NULL;
+
+ attr = find_attr (&XSTR (exp, 0), 0);
+ gcc_assert (attr);
+
+ if (attr->is_const && !attr->is_special)
+ {
+ struct insn_reserv *decl;
+
+ for (decl = all_insn_reservs; decl; decl = decl->next)
+ if (! check_tune_attr (attr->name, decl->condexp))
+ return NULL;
+ return attr;
+ }
+ return NULL;
+
+ default:
+ return NULL;
+ }
+}
+
/* Create all of the attributes that describe automaton properties. */
static void
make_automaton_attrs (void)
@@ -4379,28 +4442,154 @@ make_automaton_attrs (void)
int i;
struct insn_reserv *decl;
rtx code_exp, lats_exp, byps_exp;
+ struct attr_desc *tune_attr;
if (n_insn_reservs == 0)
return;
- code_exp = rtx_alloc (COND);
- lats_exp = rtx_alloc (COND);
+ tune_attr = find_tune_attr (all_insn_reservs->condexp);
+ if (tune_attr != NULL)
+ {
+ rtx *condexps = XNEWVEC (rtx, n_insn_reservs * 3);
+ struct attr_value *val;
+ bool first = true;
+
+ gcc_assert (tune_attr->is_const
+ && !tune_attr->is_special
+ && !tune_attr->is_numeric);
+ for (val = tune_attr->first_value; val; val = val->next)
+ {
+ if (val == tune_attr->default_val)
+ continue;
+ gcc_assert (GET_CODE (val->value) == CONST_STRING);
+ printf ("static int internal_dfa_insn_code_%s (rtx);\n"
+ "static int insn_default_latency_%s (rtx);\n",
+ XSTR (val->value, 0), XSTR (val->value, 0));
+ }
+
+ printf ("\n");
+ printf ("int (*internal_dfa_insn_code) (rtx);\n");
+ printf ("int (*insn_default_latency) (rtx);\n");
+ printf ("\n");
+ printf ("void\n");
+ printf ("init_sched_attrs (void)\n");
+ printf ("{\n");
+
+ for (val = tune_attr->first_value; val; val = val->next)
+ {
+ int j;
+ char *name;
+ rtx test = attr_rtx (EQ_ATTR, tune_attr->name, XSTR (val->value, 0));
+
+ if (val == tune_attr->default_val)
+ continue;
+ for (decl = all_insn_reservs, i = 0;
+ decl;
+ decl = decl->next)
+ {
+ rtx ctest = test;
+ rtx condexp
+ = simplify_and_tree (decl->condexp, &ctest, -2, 0);
+ if (condexp == false_rtx)
+ continue;
+ if (condexp == true_rtx)
+ break;
+ condexps[i] = condexp;
+ condexps[i + 1] = make_numeric_value (decl->insn_num);
+ condexps[i + 2] = make_numeric_value (decl->default_latency);
+ i += 3;
+ }
+
+ code_exp = rtx_alloc (COND);
+ lats_exp = rtx_alloc (COND);
+
+ j = i / 3 * 2;
+ XVEC (code_exp, 0) = rtvec_alloc (j);
+ XVEC (lats_exp, 0) = rtvec_alloc (j);
+
+ if (decl)
+ {
+ XEXP (code_exp, 1) = make_numeric_value (decl->insn_num);
+ XEXP (lats_exp, 1) = make_numeric_value (decl->default_latency);
+ }
+ else
+ {
+ XEXP (code_exp, 1) = make_numeric_value (n_insn_reservs + 1);
+ XEXP (lats_exp, 1) = make_numeric_value (0);
+ }
+
+ while (i > 0)
+ {
+ i -= 3;
+ j -= 2;
+ XVECEXP (code_exp, 0, j) = condexps[i];
+ XVECEXP (lats_exp, 0, j) = condexps[i];
+
+ XVECEXP (code_exp, 0, j + 1) = condexps[i + 1];
+ XVECEXP (lats_exp, 0, j + 1) = condexps[i + 2];
+ }
- XVEC (code_exp, 0) = rtvec_alloc (n_insn_reservs * 2);
- XVEC (lats_exp, 0) = rtvec_alloc (n_insn_reservs * 2);
+ name = XNEWVEC (char,
+ sizeof ("*internal_dfa_insn_code_")
+ + strlen (XSTR (val->value, 0)));
+ strcpy (name, "*internal_dfa_insn_code_");
+ strcat (name, XSTR (val->value, 0));
+ make_internal_attr (name, code_exp, ATTR_NONE);
+ strcpy (name, "*insn_default_latency_");
+ strcat (name, XSTR (val->value, 0));
+ make_internal_attr (name, lats_exp, ATTR_NONE);
+ XDELETEVEC (name);
- XEXP (code_exp, 1) = make_numeric_value (n_insn_reservs + 1);
- XEXP (lats_exp, 1) = make_numeric_value (0);
+ if (first)
+ {
+ printf (" if (");
+ first = false;
+ }
+ else
+ printf (" else if (");
+ write_test_expr (test, 0);
+ printf (")\n");
+ printf (" {\n");
+ printf (" internal_dfa_insn_code\n");
+ printf (" = internal_dfa_insn_code_%s;\n",
+ XSTR (val->value, 0));
+ printf (" insn_default_latency\n");
+ printf (" = insn_default_latency_%s;\n",
+ XSTR (val->value, 0));
+ printf (" }\n");
+ }
+
+ printf (" else\n");
+ printf (" gcc_unreachable ();\n");
+ printf ("}\n");
+ printf ("\n");
- for (decl = all_insn_reservs, i = 0;
- decl;
- decl = decl->next, i += 2)
+ XDELETEVEC (condexps);
+ }
+ else
{
- XVECEXP (code_exp, 0, i) = decl->condexp;
- XVECEXP (lats_exp, 0, i) = decl->condexp;
+ code_exp = rtx_alloc (COND);
+ lats_exp = rtx_alloc (COND);
+
+ XVEC (code_exp, 0) = rtvec_alloc (n_insn_reservs * 2);
+ XVEC (lats_exp, 0) = rtvec_alloc (n_insn_reservs * 2);
- XVECEXP (code_exp, 0, i+1) = make_numeric_value (decl->insn_num);
- XVECEXP (lats_exp, 0, i+1) = make_numeric_value (decl->default_latency);
+ XEXP (code_exp, 1) = make_numeric_value (n_insn_reservs + 1);
+ XEXP (lats_exp, 1) = make_numeric_value (0);
+
+ for (decl = all_insn_reservs, i = 0;
+ decl;
+ decl = decl->next, i += 2)
+ {
+ XVECEXP (code_exp, 0, i) = decl->condexp;
+ XVECEXP (lats_exp, 0, i) = decl->condexp;
+
+ XVECEXP (code_exp, 0, i+1) = make_numeric_value (decl->insn_num);
+ XVECEXP (lats_exp, 0, i+1)
+ = make_numeric_value (decl->default_latency);
+ }
+ make_internal_attr ("*internal_dfa_insn_code", code_exp, ATTR_NONE);
+ make_internal_attr ("*insn_default_latency", lats_exp, ATTR_NONE);
}
if (n_bypasses == 0)
@@ -4423,8 +4612,6 @@ make_automaton_attrs (void)
}
}
- make_internal_attr ("*internal_dfa_insn_code", code_exp, ATTR_NONE);
- make_internal_attr ("*insn_default_latency", lats_exp, ATTR_NONE);
make_internal_attr ("*bypass_p", byps_exp, ATTR_NONE);
}
--- gcc/genattr.c.jj 2010-06-11 09:38:08.000000000 +0200
+++ gcc/genattr.c 2010-06-16 19:18:10.000000000 +0200
@@ -1,6 +1,6 @@
/* Generate attribute information (insn-attr.h) from machine description.
- Copyright (C) 1991, 1994, 1996, 1998, 1999, 2000, 2003, 2004, 2007, 2008
- Free Software Foundation, Inc.
+ Copyright (C) 1991, 1994, 1996, 1998, 1999, 2000, 2003, 2004, 2007, 2008,
+ 2010 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
This file is part of GCC.
@@ -40,12 +40,18 @@ write_upcase (const char *str)
putchar (TOUPPER(*str));
}
+static VEC (rtx, heap) *const_attrs, *reservations;
+
+
static void
gen_attr (rtx attr)
{
const char *p, *tag;
int is_const = GET_CODE (XEXP (attr, 2)) == CONST;
+ if (is_const)
+ VEC_safe_push (rtx, heap, const_attrs, attr);
+
printf ("#define HAVE_ATTR_%s\n", XSTR (attr, 0));
/* If numeric attribute, don't need to write an enum. */
@@ -92,6 +98,68 @@ extern int insn_current_length (rtx);\n\
}
}
+/* Check that attribute NAME is used in define_insn_reservation condition
+ EXP. Return true if it is. */
+static bool
+check_tune_attr (const char *name, rtx exp)
+{
+ switch (GET_CODE (exp))
+ {
+ case AND:
+ if (check_tune_attr (name, XEXP (exp, 0)))
+ return true;
+ return check_tune_attr (name, XEXP (exp, 1));
+
+ case IOR:
+ return (check_tune_attr (name, XEXP (exp, 0))
+ && check_tune_attr (name, XEXP (exp, 1)));
+
+ case EQ_ATTR:
+ return strcmp (XSTR (exp, 0), name) == 0;
+
+ default:
+ return false;
+ }
+}
+
+/* Try to find a const attribute (usually cpu or tune) that is used
+ in all define_insn_reservation conditions. */
+static bool
+find_tune_attr (rtx exp)
+{
+ unsigned int i;
+ rtx attr;
+
+ switch (GET_CODE (exp))
+ {
+ case AND:
+ case IOR:
+ if (find_tune_attr (XEXP (exp, 0)))
+ return true;
+ return find_tune_attr (XEXP (exp, 1));
+
+ case EQ_ATTR:
+ if (strcmp (XSTR (exp, 0), "alternative") == 0)
+ return false;
+
+ for (i = 0; VEC_iterate (rtx, const_attrs, i, attr); i++)
+ if (strcmp (XSTR (attr, 0), XSTR (exp, 0)) == 0)
+ {
+ unsigned int j;
+ rtx resv;
+
+ for (j = 0; VEC_iterate (rtx, reservations, j, resv); j++)
+ if (! check_tune_attr (XSTR (attr, 0), XEXP (resv, 2)))
+ return false;
+ return true;
+ }
+ return false;
+
+ default:
+ return false;
+ }
+}
+
int
main (int argc, char **argv)
{
@@ -162,11 +230,16 @@ main (int argc, char **argv)
}
else if (GET_CODE (desc) == DEFINE_INSN_RESERVATION)
- num_insn_reservations++;
+ {
+ num_insn_reservations++;
+ VEC_safe_push (rtx, heap, reservations, desc);
+ }
}
if (num_insn_reservations > 0)
{
+ bool has_tune_attr
+ = find_tune_attr (XEXP (VEC_index (rtx, reservations, 0), 2));
/* Output interface for pipeline hazards recognition based on
DFA (deterministic finite state automata. */
printf ("\n#define INSN_SCHEDULING\n");
@@ -181,10 +254,24 @@ main (int argc, char **argv)
printf ("#define CPU_UNITS_QUERY 0\n");
printf ("#endif\n\n");
/* Interface itself: */
- printf ("/* Internal insn code number used by automata. */\n");
- printf ("extern int internal_dfa_insn_code (rtx);\n\n");
- printf ("/* Insn latency time defined in define_insn_reservation. */\n");
- printf ("extern int insn_default_latency (rtx);\n\n");
+ if (has_tune_attr)
+ {
+ printf ("/* Initialize fn pointers for internal_dfa_insn_code\n");
+ printf (" and insn_default_latency. */\n");
+ printf ("extern void init_sched_attrs (void);\n\n");
+ printf ("/* Internal insn code number used by automata. */\n");
+ printf ("extern int (*internal_dfa_insn_code) (rtx);\n\n");
+ printf ("/* Insn latency time defined in define_insn_reservation. */\n");
+ printf ("extern int (*insn_default_latency) (rtx);\n\n");
+ }
+ else
+ {
+ printf ("#define init_sched_attrs() do { } while (0)\n\n");
+ printf ("/* Internal insn code number used by automata. */\n");
+ printf ("extern int internal_dfa_insn_code (rtx);\n\n");
+ printf ("/* Insn latency time defined in define_insn_reservation. */\n");
+ printf ("extern int insn_default_latency (rtx);\n\n");
+ }
printf ("/* Return nonzero if there is a bypass for given insn\n");
printf (" which is a data producer. */\n");
printf ("extern int bypass_p (rtx);\n\n");
--- gcc/cfgexpand.c.jj 2010-06-07 11:24:33.000000000 +0200
+++ gcc/cfgexpand.c 2010-06-16 18:41:04.000000000 +0200
@@ -47,6 +47,7 @@ along with GCC; see the file COPYING3.
#include "ssaexpand.h"
#include "bitmap.h"
#include "sbitmap.h"
+#include "insn-attr.h" /* For INSN_SCHEDULING. */
/* This variable holds information helping the rewriting of SSA trees
into RTL. */
@@ -3761,6 +3762,10 @@ gimple_expand_cfg (void)
set_curr_insn_block (DECL_INITIAL (current_function_decl));
prologue_locator = curr_insn_locator ();
+#ifdef INSN_SCHEDULING
+ init_sched_attrs ();
+#endif
+
/* Make sure first insn is a note even if we don't want linenums.
This makes sure the first insn will never be deleted.
Also, final expects a note to appear there. */
Jakub