From patchwork Wed Jun 16 19:09:24 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: Speed up genattrtab Date: Wed, 16 Jun 2010 09:09:24 -0000 From: Jakub Jelinek X-Patchwork-Id: 55924 Message-Id: <20100616190924.GQ7811@tyan-ft48-01.lab.bos.redhat.com> To: gcc-patches@gcc.gnu.org Cc: Mark Mitchell , Jan Hubicka , Michael Matz 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 * 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. Jakub --- 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. */