The following patch^Whack splits $subject files into three, one for the predicates (due to an implementation detail) and two for the rest - for now into similar LOC size files.
I'd like to get help on the makefile changes to make them less verbose, somehow globbing the -[12p] parts. Also you can see the split point is manually chosen which means it will bitrot. Timings for the stage2 compiles on a x86_64 box are gimple-match-p.c 5s generic-match-p.c 3s gimple-match-1.c 85s generic-match-1.c 56s gimple-match-2.c 82s generic-match-2.c 31s the required header files are quite big (and of course everything needs to be exported without the analysis work becoming too cumbersome), it's 3342 LOC for gimple-match-head.h and 1556 LOC for generic-match-head.h The machine I tested is quite fast so the 80ish second timings are still too slow I guess and thus splitting up into four files for gimple and three files for generic looks better. Note we lose some inlining/cloning capability in the splitting process (I see quite a bit of constprop/isra work being done on the generated files). I didn't try to measure the runtime impact though. The patch still needs quite some TLC, it really is a bit hacky but I'd like to get feedback on the approach and I didn't want to spend time on programatically finding optimal split points (so everything is output in the same semi-random order as before). Richard. <insert ChangeLog here> Index: gcc/genmatch.c =================================================================== --- gcc/genmatch.c (revision 259638) +++ gcc/genmatch.c (working copy) @@ -1641,7 +1641,7 @@ struct decision_tree dt_node *root; void insert (struct simplify *, unsigned); - void gen (FILE *f, bool gimple); + void gen (const char *, FILE *, vec<unsigned long> &, bool gimple); void print (FILE *f = stderr); decision_tree () { root = new dt_node (dt_node::DT_NODE, NULL); } @@ -3608,12 +3608,25 @@ sinfo_hashmap_traits::equal_keys (const return compare_op (v->s->result, v->s, candidate->s->result, candidate->s); } +/* Write the common header for the GIMPLE/GENERIC IL matching routines. */ + +static void +write_header (FILE *f, bool gimple) +{ + fprintf (f, "/* Generated automatically by the program `genmatch' from\n"); + fprintf (f, " a IL pattern matching and simplification description. */\n"); + + /* Include the header instead of writing it awkwardly quoted here. */ + fprintf (f, "\n#include \"%s-match-head.c\"\n", + gimple ? "gimple" : "generic"); +} /* Main entry to generate code for matching GIMPLE IL off the decision tree. */ void -decision_tree::gen (FILE *f, bool gimple) +decision_tree::gen (const char *output, FILE *headerf, + vec<unsigned long> &pieces, bool gimple) { sinfo_map_t si; @@ -3624,6 +3637,34 @@ decision_tree::gen (FILE *f, bool gimple gimple ? "GIMPLE" : "GENERIC", root->num_leafs, root->max_level, root->total_size); + FILE *f; + char *outputtem = NULL; + if (output) + outputtem = XNEWVEC (char, strlen (output) + strlen ("-1.c") + 1); + + unsigned do_header = headerf ? 2 : 1; + unsigned n_per_part = -1U; + unsigned file_n = output ? 1 : 2; + do + { + unsigned n_fn = 0; + do_header--; + + if (do_header) + f = headerf; + else if (!output) + f = stdout; + else + { + sprintf (outputtem, "%s-%d.c", output, file_n++); + f = fopen (outputtem, "w"); + if (!f) + { + perror ("failed to open output file"); + exit(1); + } + write_header (f, gimple); + } /* First split out the transform part of equal leafs. */ unsigned rcnt = 0; unsigned fcnt = 1; @@ -3643,21 +3684,22 @@ decision_tree::gen (FILE *f, bool gimple } /* Generate a split out function with the leaf transform code. */ + if (do_header || !output) s->fname = xasprintf ("%s_simplify_%u", gimple ? "gimple" : "generic", fcnt++); if (gimple) - fprintf (f, "\nstatic bool\n" + fprintf (f, "\n%sbool\n" "%s (code_helper *res_code, tree *res_ops,\n" " gimple_seq *seq, tree (*valueize)(tree) " "ATTRIBUTE_UNUSED,\n" " const tree ARG_UNUSED (type), tree *ARG_UNUSED " "(captures)\n", - s->fname); + headerf ? "" : "static ", s->fname); else { - fprintf (f, "\nstatic tree\n" + fprintf (f, "\n%stree\n" "%s (location_t ARG_UNUSED (loc), const tree ARG_UNUSED (type),\n", - (*iter).second->fname); + headerf ? "" : "static ", (*iter).second->fname); for (unsigned i = 0; i < as_a <expr *>(s->s->s->match)->ops.length (); ++i) fprintf (f, " tree ARG_UNUSED (op%d),", i); @@ -3674,7 +3716,12 @@ decision_tree::gen (FILE *f, bool gimple fprintf (f, ", const combined_fn ARG_UNUSED (%s)", s->s->s->for_subst_vec[i].first->id); } - + n_fn++; + if (do_header) + { + fprintf (f, ");\n"); + continue; + } fprintf (f, ")\n{\n"); s->s->gen_1 (f, 2, gimple, s->s->s->result); if (gimple) @@ -3682,7 +3729,22 @@ decision_tree::gen (FILE *f, bool gimple else fprintf (f, " return NULL_TREE;\n"); fprintf (f, "}\n"); + + if (n_fn == pieces[file_n - 2]) + { + fclose (f); + sprintf (outputtem, "%s-%d.c", output, file_n++); + f = fopen (outputtem, "w"); + if (!f) + { + perror ("failed to open output file"); + exit(1); + } + write_header (f, gimple); + n_fn = 0; + } } + if (!do_header) fprintf (stderr, "removed %u duplicate tails\n", rcnt); for (unsigned n = 1; n <= 3; ++n) @@ -3702,20 +3764,26 @@ decision_tree::gen (FILE *f, bool gimple continue; if (gimple) - fprintf (f, "\nstatic bool\n" + fprintf (f, "\n%sbool\n" "gimple_simplify_%s (code_helper *res_code, tree *res_ops,\n" " gimple_seq *seq, tree (*valueize)(tree) " "ATTRIBUTE_UNUSED,\n" " code_helper ARG_UNUSED (code), tree " "ARG_UNUSED (type)\n", - e->operation->id); + headerf ? "" : "static ", e->operation->id); else - fprintf (f, "\nstatic tree\n" + fprintf (f, "\n%stree\n" "generic_simplify_%s (location_t ARG_UNUSED (loc), enum " "tree_code ARG_UNUSED (code), const tree ARG_UNUSED (type)", - e->operation->id); + headerf ? "" : "static ", e->operation->id); for (unsigned i = 0; i < n; ++i) fprintf (f, ", tree op%d", i); + n_fn++; + if (do_header) + { + fprintf (f, ");\n"); + continue; + } fprintf (f, ")\n"); fprintf (f, "{\n"); dop->gen_kids (f, 2, gimple); @@ -3724,21 +3792,43 @@ decision_tree::gen (FILE *f, bool gimple else fprintf (f, " return NULL_TREE;\n"); fprintf (f, "}\n"); + + if (n_fn == pieces[file_n - 2]) + { + fclose (f); + sprintf (outputtem, "%s-%d.c", output, file_n++); + f = fopen (outputtem, "w"); + if (!f) + { + perror ("failed to open output file"); + exit(1); + } + write_header (f, gimple); + n_fn = 0; + } + } /* Then generate the main entry with the outermost switch and tail-calls to the split-out functions. */ if (gimple) - fprintf (f, "\nstatic bool\n" + fprintf (f, "\n%sbool\n" "gimple_simplify (code_helper *res_code, tree *res_ops,\n" " gimple_seq *seq, tree (*valueize)(tree),\n" - " code_helper code, const tree type"); + " code_helper code, const tree type", + headerf ? "" : "static "); else fprintf (f, "\ntree\n" "generic_simplify (location_t loc, enum tree_code code, " "const tree type ATTRIBUTE_UNUSED"); for (unsigned i = 0; i < n; ++i) fprintf (f, ", tree op%d", i); + n_fn++; + if (do_header) + { + fprintf (f, ");\n"); + continue; + } fprintf (f, ")\n"); fprintf (f, "{\n"); @@ -3786,19 +3876,46 @@ decision_tree::gen (FILE *f, bool gimple else fprintf (f, " return NULL_TREE;\n"); fprintf (f, "}\n"); + if (n_fn == pieces[file_n - 2]) + { + fclose (f); + sprintf (outputtem, "%s-%d.c", output, file_n++); + f = fopen (outputtem, "w"); + if (!f) + { + perror ("failed to open output file"); + exit(1); + } + write_header (f, gimple); + n_fn = 0; + } + } + + n_per_part = n_fn / 4 + 1; } + while (do_header); + if (output) + fclose (f); } /* Output code to implement the predicate P from the decision tree DT. */ void -write_predicate (FILE *f, predicate_id *p, decision_tree &dt, bool gimple) +write_predicate (FILE *f, predicate_id *p, decision_tree &dt, bool gimple, + bool for_header) { fprintf (f, "\nbool\n" - "%s%s (tree t%s%s)\n" - "{\n", gimple ? "gimple_" : "tree_", p->id, + "%s%s (tree t%s%s)", + gimple ? "gimple_" : "tree_", p->id, p->nargs > 0 ? ", tree *res_ops" : "", gimple ? ", tree (*valueize)(tree) ATTRIBUTE_UNUSED" : ""); + if (for_header) + { + fprintf (f, ";\n"); + return; + } + + fprintf (f, "\n{\n"); /* Conveniently make 'type' available. */ fprintf_indent (f, 2, "const tree type = TREE_TYPE (t);\n"); @@ -3810,18 +3927,6 @@ write_predicate (FILE *f, predicate_id * "}\n"); } -/* Write the common header for the GIMPLE/GENERIC IL matching routines. */ - -static void -write_header (FILE *f, const char *head) -{ - fprintf (f, "/* Generated automatically by the program `genmatch' from\n"); - fprintf (f, " a IL pattern matching and simplification description. */\n"); - - /* Include the header instead of writing it awkwardly quoted here. */ - fprintf (f, "\n#include \"%s\"\n", head); -} - /* AST parsing. */ @@ -4969,6 +5074,9 @@ main (int argc, char **argv) bool gimple = true; char *input = argv[argc-1]; + char *output = NULL; + char *header = NULL; + auto_vec<unsigned long> pieces; for (int i = 1; i < argc - 1; ++i) { if (strcmp (argv[i], "--gimple") == 0) @@ -4979,13 +5087,25 @@ main (int argc, char **argv) verbose = 1; else if (strcmp (argv[i], "-vv") == 0) verbose = 2; + else if (strcmp (argv[i], "-c") == 0) + { + char *endp; + output = argv[++i]; + while (i + 1 < argc - 1 + && ISDIGIT (argv[i + 1][0])) + pieces.safe_push (strtoul (argv[++i], &endp, 10)); + } + else if (strcmp (argv[i], "-h") == 0) + header = argv[++i]; else { fprintf (stderr, "Usage: genmatch " - "[--gimple] [--generic] [-v[v]] input\n"); + "[--gimple] [--generic] [-v[v]] " + "[-c output num...] [-h header] input\n"); return 1; } } + pieces.safe_push (-1UL); line_table = XCNEW (struct line_maps); linemap_init (line_table, 0); @@ -5039,10 +5159,32 @@ add_operator (VIEW_CONVERT2, "view_conve /* Parse ahead! */ parser p (r); - if (gimple) - write_header (stdout, "gimple-match-head.c"); + FILE *f, *headerf = NULL; + if (!output) + f = stdout; else - write_header (stdout, "generic-match-head.c"); + { + char *outputtem = XNEWVEC (char, strlen (output) + strlen ("-1.c") + 1); + sprintf (outputtem, "%s-p.c", output); + f = fopen (outputtem, "w"); + if (!f) + { + perror ("failed to open output file"); + exit(1); + } + } + if (header) + { + headerf = fopen (header, "w"); + if (!headerf) + { + perror ("failed to open output file"); + exit(1); + } + } + + fprintf (f, "#define GENFOO_MAIN_FILE 1\n"); + write_header (f, gimple); /* Go over all predicates defined with patterns and perform lowering and code generation. */ @@ -5062,8 +5204,12 @@ add_operator (VIEW_CONVERT2, "view_conve if (verbose == 2) dt.print (stderr); - write_predicate (stdout, pred, dt, gimple); + if (header) + write_predicate (headerf, pred, dt, gimple, true); + write_predicate (f, pred, dt, gimple, false); } + if (output) + fclose (f); /* Lower the main simplifiers and generate code for them. */ lower (p.simplifiers, gimple); @@ -5079,7 +5225,10 @@ add_operator (VIEW_CONVERT2, "view_conve if (verbose == 2) dt.print (stderr); - dt.gen (stdout, gimple); + dt.gen (output, headerf, pieces, gimple); + + if (header) + fclose (headerf); /* Finalize. */ cpp_finish (r, NULL); Index: gcc/gimple-match-head.c =================================================================== --- gcc/gimple-match-head.c (revision 259638) +++ gcc/gimple-match-head.c (working copy) @@ -40,21 +40,10 @@ along with GCC; see the file COPYING3. #include "case-cfn-macros.h" #include "gimplify.h" #include "optabs-tree.h" +#include "gimple-match-head.h" -/* Forward declarations of the private auto-generated matchers. - They expect valueized operands in canonical order and do not - perform simplification of all-constant operands. */ -static bool gimple_simplify (code_helper *, tree *, - gimple_seq *, tree (*)(tree), - code_helper, tree, tree); -static bool gimple_simplify (code_helper *, tree *, - gimple_seq *, tree (*)(tree), - code_helper, tree, tree, tree); -static bool gimple_simplify (code_helper *, tree *, - gimple_seq *, tree (*)(tree), - code_helper, tree, tree, tree, tree); - +#if GENFOO_MAIN_FILE /* Return whether T is a constant that we'll dispatch to fold to evaluate fully constant expressions. */ @@ -772,6 +761,8 @@ gimple_simplify (gimple *stmt, return false; } +#endif + /* Helper for the autogenerated code, valueize OP. */ Index: gcc/generic-match-head.c =================================================================== --- gcc/generic-match-head.c (revision 259638) +++ gcc/generic-match-head.c (working copy) @@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. #include "case-cfn-macros.h" #include "gimplify.h" #include "optabs-tree.h" +#include "generic-match-head.h" /* Routine to determine if the types T1 and T2 are effectively Index: gcc/Makefile.in =================================================================== --- gcc/Makefile.in (revision 259638) +++ gcc/Makefile.in (working copy) @@ -216,8 +216,12 @@ gengtype-lex.o-warn = -Wno-error libgcov-util.o-warn = -Wno-error libgcov-driver-tool.o-warn = -Wno-error libgcov-merge-tool.o-warn = -Wno-error -gimple-match.o-warn = -Wno-unused -generic-match.o-warn = -Wno-unused +gimple-match-p.o-warn = -Wno-unused +gimple-match-1.o-warn = -Wno-unused +gimple-match-2.o-warn = -Wno-unused +generic-match-p.o-warn = -Wno-unused +generic-match-1.o-warn = -Wno-unused +generic-match-2.o-warn = -Wno-unused dfp.o-warn = -Wno-strict-aliasing # All warnings have to be shut off in stage1 if the compiler used then @@ -771,7 +775,7 @@ COMPILERS = @all_compilers@ # List of things which should already be built whenever we try to use xgcc # to compile anything (without linking). -GCC_PASSES=xgcc$(exeext) specs +GCC_PASSES=xgcc$(exeext) # Directory to link to, when using the target `maketest'. DIR = ../gcc @@ -1207,8 +1211,12 @@ C_COMMON_OBJS = c-family/c-common.o c-fa # will build them sooner, because they are large and otherwise tend to be # the last objects to finish building. OBJS = \ - gimple-match.o \ - generic-match.o \ + gimple-match-p.o \ + generic-match-p.o \ + gimple-match-1.o \ + generic-match-1.o \ + gimple-match-2.o \ + generic-match-2.o \ insn-attrtab.o \ insn-automata.o \ insn-dfatab.o \ @@ -1654,7 +1662,9 @@ MOSTLYCLEANFILES = insn-flags.h insn-con insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \ insn-attr.h insn-attr-common.h insn-attrtab.c insn-dfatab.c \ insn-latencytab.c insn-opinit.c insn-opinit.h insn-preds.c insn-constants.h \ - tm-preds.h tm-constrs.h checksum-options gimple-match.c generic-match.c \ + tm-preds.h tm-constrs.h checksum-options gimple-match-head.h gimple-match-1.c \ + gimple-match-2.c gimple-match-p.c generic-match-head.h generic-match-1.c \ + generic-match-p.c generic-match-2.c \ tree-check.h min-insn-modes.c insn-modes.c insn-modes.h insn-modes-inline.h \ genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list \ case-cfn-macros.h cfn-operators.pd \ @@ -1899,7 +1909,7 @@ all.internal: start.encap rest.encap doc all.cross: native gcc-cross$(exeext) cpp$(exeext) specs \ libgcc-support lang.all.cross doc selftest @GENINSRC@ srcextra # This is what must be made before installing GCC and converting libraries. -start.encap: native xgcc$(exeext) cpp$(exeext) specs \ +start.encap: native xgcc$(exeext) cpp$(exeext) \ libgcc-support lang.start.encap @GENINSRC@ srcextra # These can't be made until after GCC can run. rest.encap: lang.rest.encap @@ -2054,7 +2064,7 @@ checksum-options: libgcc-support: libgcc.mvars stmp-int-hdrs $(TCONFIG_H) \ $(MACHMODE_H) gcov-iov.h -libgcc.mvars: config.status Makefile specs xgcc$(exeext) +libgcc.mvars: config.status Makefile xgcc$(exeext) : > tmp-libgcc.mvars echo GCC_CFLAGS = '$(GCC_CFLAGS)' >> tmp-libgcc.mvars echo INHIBIT_LIBC_CFLAGS = '$(INHIBIT_LIBC_CFLAGS)' >> tmp-libgcc.mvars @@ -2271,8 +2281,9 @@ $(common_out_object_file): $(common_out_ .PRECIOUS: insn-config.h insn-flags.h insn-codes.h insn-constants.h \ insn-emit.c insn-recog.c insn-extract.c insn-output.c insn-peep.c \ insn-attr.h insn-attr-common.h insn-attrtab.c insn-dfatab.c \ - insn-latencytab.c insn-preds.c gimple-match.c generic-match.c \ - insn-target-def.h + insn-latencytab.c insn-preds.c gimple-match-head.h gimple-match-1.c \ + gimple-match-2.c generic-match-head.h generic-match-1.c generic-match-2.c \ + gimple-match-p.c generic-match-p.c insn-target-def.h # Dependencies for the md file. The first time through, we just assume # the md file itself and the generated dependency file (in order to get @@ -2504,18 +2515,36 @@ s-tm-texi: build/genhooks$(build_exeext) false; \ fi -gimple-match.c: s-match gimple-match-head.c ; @true -generic-match.c: s-match generic-match-head.c ; @true +gimple-match-p.c: s-match gimple-match-head.c ; @true +gimple-match-1.c: s-match gimple-match-head.c ; @true +gimple-match-2.c: s-match gimple-match-head.c ; @true +generic-match-p.c: s-match generic-match-head.c ; @true +generic-match-1.c: s-match generic-match-head.c ; @true +generic-match-2.c: s-match generic-match-head.c ; @true s-match: build/genmatch$(build_exeext) $(srcdir)/match.pd cfn-operators.pd - $(RUN_GEN) build/genmatch$(build_exeext) --gimple $(srcdir)/match.pd \ - > tmp-gimple-match.c - $(RUN_GEN) build/genmatch$(build_exeext) --generic $(srcdir)/match.pd \ - > tmp-generic-match.c - $(SHELL) $(srcdir)/../move-if-change tmp-gimple-match.c \ - gimple-match.c - $(SHELL) $(srcdir)/../move-if-change tmp-generic-match.c \ - generic-match.c + $(RUN_GEN) build/genmatch$(build_exeext) --gimple \ + -h tmp-gimple-match-head.h -c tmp-gimple-match 460 \ + $(srcdir)/match.pd + $(RUN_GEN) build/genmatch$(build_exeext) --generic \ + -h tmp-generic-match-head.h -c tmp-generic-match 290 \ + $(srcdir)/match.pd + $(SHELL) $(srcdir)/../move-if-change tmp-gimple-match-head.h \ + gimple-match-head.h + $(SHELL) $(srcdir)/../move-if-change tmp-gimple-match-1.c \ + gimple-match-1.c + $(SHELL) $(srcdir)/../move-if-change tmp-gimple-match-2.c \ + gimple-match-2.c + $(SHELL) $(srcdir)/../move-if-change tmp-gimple-match-p.c \ + gimple-match-p.c + $(SHELL) $(srcdir)/../move-if-change tmp-generic-match-head.h \ + generic-match-head.h + $(SHELL) $(srcdir)/../move-if-change tmp-generic-match-1.c \ + generic-match-1.c + $(SHELL) $(srcdir)/../move-if-change tmp-generic-match-2.c \ + generic-match-2.c + $(SHELL) $(srcdir)/../move-if-change tmp-generic-match-p.c \ + generic-match-p.c $(STAMP) s-match GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \