va_end (ap);
}
+/* Like fprintf, but print to two files, one header one C implementation. */
+FILE *header_file = NULL;
+
+static void
+#if GCC_VERSION >= 4001
+__attribute__((format (printf, 4, 5)))
+#endif
+emit_func (FILE *f, bool open, bool close, const char *format, ...)
+{
+ va_list ap1, ap2;
+ if (header_file != NULL)
+ {
+ if (open)
+ fprintf (header_file, "extern ");
+ va_start (ap2, format);
+ vfprintf (header_file, format, ap2);
+ va_end (ap2);
+ if (close)
+ fprintf (header_file, ";\n");
+ }
+
+ va_start (ap1, format);
+ vfprintf (f, format, ap1);
+ va_end (ap1);
+ fputc ('\n', f);
+}
+
static void
output_line_directive (FILE *f, location_t location,
bool dumpfile = false, bool fnargs = false)
fprintf (f, "/* #line %d \"%s\" */\n", loc.line, loc.file);
}
+/* Find the file to write into next. We try to evenly distribute the contents
+ over the different files. */
+
+#define SIZED_BASED_CHUNKS 1
+
+int current_file = 0;
+FILE *get_out_file (vec <FILE *> &parts)
+{
+#ifdef SIZED_BASED_CHUNKS
+ if (parts.length () == 1)
+ return parts[0];
+
+ FILE *f = NULL;
+ long min = 0;
+ /* We've started writing all the files at pos 0, so ftell is equivalent
+ to the size and should be much faster. */
+ for (unsigned i = 0; i < parts.length (); i++)
+ {
+ long res = ftell (parts[i]);
+ if (!f || res < min)
+ {
+ min = res;
+ f = parts[i];
+ }
+ }
+ return f;
+#else
+ return parts[current_file++ % parts.length ()];
+#endif
+}
+
/* Pull in tree codes and builtin function codes from their
definition files. */
dt_node *root;
void insert (class simplify *, unsigned);
- void gen (FILE *f, bool gimple);
+ void gen (vec <FILE *> &f, bool gimple);
void print (FILE *f = stderr);
decision_tree () { root = new dt_node (dt_node::DT_NODE, NULL); }
tree. */
void
-decision_tree::gen (FILE *f, bool gimple)
+decision_tree::gen (vec <FILE *> &files, bool gimple)
{
sinfo_map_t si;
output_line_directive (stderr, s->s->s->result->location);
}
+ /* Cycle the file buffers. */
+ FILE *f = get_out_file (files);
+
/* Generate a split out function with the leaf transform code. */
s->fname = xasprintf ("%s_simplify_%u", gimple ? "gimple" : "generic",
fcnt++);
if (gimple)
- fprintf (f, "\nstatic bool\n"
+ emit_func (f, true, false, "\nbool\n"
"%s (gimple_match_op *res_op, gimple_seq *seq,\n"
" tree (*valueize)(tree) ATTRIBUTE_UNUSED,\n"
" const tree ARG_UNUSED (type), tree *ARG_UNUSED "
s->fname);
else
{
- fprintf (f, "\nstatic tree\n"
+ emit_func (f, true, false, "\ntree\n"
"%s (location_t ARG_UNUSED (loc), const tree ARG_UNUSED (type),\n",
(*iter).second->fname);
for (unsigned i = 0;
i < as_a <expr *>(s->s->s->match)->ops.length (); ++i)
- fprintf (f, " tree ARG_UNUSED (_p%d),", i);
- fprintf (f, " tree *captures\n");
+ emit_func (f, false, false, " tree ARG_UNUSED (_p%d),", i);
+ emit_func (f, false, false, " tree *captures\n");
}
for (unsigned i = 0; i < s->s->s->for_subst_vec.length (); ++i)
{
if (! s->s->s->for_subst_vec[i].first->used)
continue;
if (is_a <operator_id *> (s->s->s->for_subst_vec[i].second))
- fprintf (f, ", const enum tree_code ARG_UNUSED (%s)",
+ emit_func (f, false, false, ", const enum tree_code ARG_UNUSED (%s)",
s->s->s->for_subst_vec[i].first->id);
else if (is_a <fn_id *> (s->s->s->for_subst_vec[i].second))
- fprintf (f, ", const combined_fn ARG_UNUSED (%s)",
+ emit_func (f, false, false, ", const combined_fn ARG_UNUSED (%s)",
s->s->s->for_subst_vec[i].first->id);
}
- fprintf (f, ")\n{\n");
+ emit_func (f, false, true, ")");
+ fprintf (f, "{\n");
fprintf_indent (f, 2, "const bool debug_dump = "
"dump_file && (dump_flags & TDF_FOLDING);\n");
s->s->gen_1 (f, 2, gimple, s->s->s->result);
&& e->operation->kind != id_base::CODE))
continue;
+
+ /* Cycle the file buffers. */
+ FILE *f = get_out_file (files);
+
if (gimple)
- fprintf (f, "\nstatic bool\n"
+ emit_func (f, true, false,"\nbool\n"
"gimple_simplify_%s (gimple_match_op *res_op,"
" gimple_seq *seq,\n"
" tree (*valueize)(tree) "
"ARG_UNUSED (type)\n",
e->operation->id);
else
- fprintf (f, "\nstatic tree\n"
+ emit_func (f, true, false, "\ntree\n"
"generic_simplify_%s (location_t ARG_UNUSED (loc), enum "
"tree_code ARG_UNUSED (code), const tree ARG_UNUSED (type)",
e->operation->id);
for (unsigned i = 0; i < n; ++i)
- fprintf (f, ", tree _p%d", i);
- fprintf (f, ")\n");
+ emit_func (f, false, false,", tree _p%d", i);
+ emit_func (f, false, true, ")");
fprintf (f, "{\n");
fprintf_indent (f, 2, "const bool debug_dump = "
"dump_file && (dump_flags & TDF_FOLDING);\n");
with compiler warnings, by generating a simple stub. */
if (! has_kids_p)
{
+
+ /* Cycle the file buffers. */
+ FILE *f = get_out_file (files);
+
if (gimple)
- fprintf (f, "\nbool\n"
+ emit_func (f, true, false, "\nbool\n"
"gimple_simplify (gimple_match_op*, gimple_seq*,\n"
" tree (*)(tree), code_helper,\n"
" const tree");
else
- fprintf (f, "\ntree\n"
+ emit_func (f, true, false,"\ntree\n"
"generic_simplify (location_t, enum tree_code,\n"
" const tree");
for (unsigned i = 0; i < n; ++i)
- fprintf (f, ", tree");
- fprintf (f, ")\n");
+ emit_func (f, false, false, ", tree");
+ emit_func (f, false, true, ")");
fprintf (f, "{\n");
if (gimple)
fprintf (f, " return false;\n");
continue;
}
+
+ /* Cycle the file buffers. */
+ FILE *f = get_out_file (files);
+
/* Then generate the main entry with the outermost switch and
tail-calls to the split-out functions. */
if (gimple)
- fprintf (f, "\nbool\n"
+ emit_func (f, true, false, "\nbool\n"
"gimple_simplify (gimple_match_op *res_op, gimple_seq *seq,\n"
" tree (*valueize)(tree) ATTRIBUTE_UNUSED,\n"
" code_helper code, const tree type");
else
- fprintf (f, "\ntree\n"
+ emit_func (f, true, false, "\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 _p%d", i);
- fprintf (f, ")\n");
+ emit_func (f, false, false, ", tree _p%d", i);
+ emit_func (f, false, true, ")");
fprintf (f, "{\n");
if (gimple)
void
write_predicate (FILE *f, predicate_id *p, decision_tree &dt, bool gimple)
{
- fprintf (f, "\nbool\n"
- "%s%s (tree t%s%s)\n"
- "{\n", gimple ? "gimple_" : "tree_", p->id,
- p->nargs > 0 ? ", tree *res_ops" : "",
- gimple ? ", tree (*valueize)(tree) ATTRIBUTE_UNUSED" : "");
+ emit_func (f, true, true, "\nbool\n%s%s (tree t%s%s)",
+ gimple ? "gimple_" : "tree_", p->id,
+ p->nargs > 0 ? ", tree *res_ops" : "",
+ gimple ? ", tree (*valueize)(tree) ATTRIBUTE_UNUSED" : "");
+ fprintf (f, "{\n");
/* Conveniently make 'type' available. */
fprintf_indent (f, 2, "const tree type = TREE_TYPE (t);\n");
fprintf_indent (f, 2, "const bool debug_dump = "
{
fprintf (f, "/* Generated automatically by the program `genmatch' from\n");
fprintf (f, " a IL pattern matching and simplification description. */\n");
+ fprintf (f, "#pragma GCC diagnostic push\n");
+ fprintf (f, "#pragma GCC diagnostic ignored \"-Wunused-variable\"\n");
+ fprintf (f, "#pragma GCC diagnostic ignored \"-Wunused-function\"\n");
/* Include the header instead of writing it awkwardly quoted here. */
- fprintf (f, "\n#include \"%s\"\n", head);
+ if (head)
+ fprintf (f, "\n#include \"%s\"\n", head);
}
}
+/* Construct and display the help menu. */
+
+static void
+showUsage ()
+{
+ fprintf (stderr, "Usage: genmatch [--gimple] [--generic] "
+ "[--header=<filename>] [--include=<filename>] [-v[v]] input "
+ "[<outputfile>...]\n");
+ fprintf (stderr, "\nWhen more then one outputfile is specified --header "
+ "is required.\n");
+}
+
+/* Write out the correct include to the match-head fle containing the helper
+ files. */
+
+static void
+write_header_includes (bool gimple, FILE *header_file)
+{
+ if (gimple)
+ fprintf (header_file, "#include \"gimple-match-head.cc\"\n");
+ else
+ fprintf (header_file, "#include \"generic-match-head.cc\"\n");
+}
+
/* The genmatch generator program. It reads from a pattern description
and outputs GIMPLE or GENERIC IL matching and simplification routines. */
return 1;
bool gimple = true;
- char *input = argv[argc-1];
- for (int i = 1; i < argc - 1; ++i)
+ char *s_header_file = NULL;
+ char *s_include_file = NULL;
+ auto_vec <char *> files;
+ char *input = NULL;
+ int last_file = argc - 1;
+ for (int i = argc - 1; i >= 1; --i)
{
if (strcmp (argv[i], "--gimple") == 0)
gimple = true;
else if (strcmp (argv[i], "--generic") == 0)
gimple = false;
+ else if (strncmp (argv[i], "--header=", 9) == 0)
+ s_header_file = &argv[i][9];
+ else if (strncmp (argv[i], "--include=", 10) == 0)
+ s_include_file = &argv[i][10];
else if (strcmp (argv[i], "-v") == 0)
verbose = 1;
else if (strcmp (argv[i], "-vv") == 0)
verbose = 2;
+ else if (strncmp (argv[i], "--", 2) != 0 && last_file-- == i)
+ files.safe_push (argv[i]);
else
{
- fprintf (stderr, "Usage: genmatch "
- "[--gimple] [--generic] [-v[v]] input\n");
+ showUsage ();
return 1;
}
}
+ /* Validate if the combinations are valid. */
+ if ((files.length () > 1 && !s_header_file) || files.is_empty ())
+ showUsage ();
+
+ if (!s_include_file)
+ s_include_file = s_header_file;
+
+ /* Input file is the last in the reverse list. */
+ input = files.pop ();
+
line_table = XCNEW (class line_maps);
linemap_init (line_table, 0);
line_table->reallocator = xrealloc;
/* Parse ahead! */
parser p (r, gimple);
- if (gimple)
- write_header (stdout, "gimple-match-head.cc");
+ /* Create file buffers. */
+ int n_parts = files.is_empty () ? 1 : files.length ();
+ auto_vec <FILE *> parts (n_parts);
+ if (files.is_empty ())
+ {
+ parts.quick_push (stdout);
+ write_header (stdout, s_include_file);
+ write_header_includes (gimple, stdout);
+ }
else
- write_header (stdout, "generic-match-head.cc");
+ {
+ for (char *s_file : files)
+ {
+ parts.quick_push (fopen (s_file, "w"));
+ write_header (parts.last (), s_include_file);
+ }
+
+ header_file = fopen (s_header_file, "w");
+ fprintf (header_file, "#ifndef GCC_GIMPLE_MATCH_AUTO_H\n"
+ "#define GCC_GIMPLE_MATCH_AUTO_H\n");
+ write_header_includes (gimple, header_file);
+ }
/* Go over all predicates defined with patterns and perform
lowering and code generation. */
if (verbose == 2)
dt.print (stderr);
- write_predicate (stdout, pred, dt, gimple);
+ /* Cycle the file buffers. */
+ FILE *f = get_out_file (parts);
+
+ write_predicate (f, pred, dt, gimple);
}
/* Lower the main simplifiers and generate code for them. */
if (verbose == 2)
dt.print (stderr);
- dt.gen (stdout, gimple);
+ dt.gen (parts, gimple);
+
+ for (FILE *f : parts)
+ {
+ fprintf (f, "#pragma GCC diagnostic pop\n");
+ fclose (f);
+ }
+
+ if (header_file)
+ {
+ fprintf (header_file, "#endif /* GCC_GIMPLE_MATCH_AUTO_H. */\n");
+ fclose (header_file);
+ }
/* Finalize. */
cpp_finish (r, NULL);