summaryrefslogtreecommitdiff
path: root/gcc/genopinit.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2018-01-25 08:49:33 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2018-01-25 08:49:33 +0000
commit8bbc33baa40010c8f5ca1af9b8bfffd67ae654ad (patch)
treec5e2748190eff9453ae08b9117c4c546c48cc539 /gcc/genopinit.c
parent03ac50856c9fc8c96b7a17239ee40a10397750a7 (diff)
downloadgcc-tarball-8bbc33baa40010c8f5ca1af9b8bfffd67ae654ad.tar.gz
Diffstat (limited to 'gcc/genopinit.c')
-rw-r--r--gcc/genopinit.c382
1 files changed, 382 insertions, 0 deletions
diff --git a/gcc/genopinit.c b/gcc/genopinit.c
new file mode 100644
index 0000000000..d98fcd56e2
--- /dev/null
+++ b/gcc/genopinit.c
@@ -0,0 +1,382 @@
+/* Generate code to initialize optabs from machine description.
+ Copyright (C) 1993-2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+
+#include "bconfig.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "errors.h"
+#include "gensupport.h"
+
+
+#define DEF_RTL_EXPR(V, N, X, C) #V,
+
+static const char * const rtx_upname[] = {
+#include "rtl.def"
+};
+
+#undef DEF_RTL_EXPR
+
+/* Vector in which to collect insns that match. */
+static vec<optab_pattern> patterns;
+
+static void
+gen_insn (md_rtx_info *info)
+{
+ optab_pattern p;
+ if (find_optab (&p, XSTR (info->def, 0)))
+ patterns.safe_push (p);
+}
+
+static int
+pattern_cmp (const void *va, const void *vb)
+{
+ const optab_pattern *a = (const optab_pattern *)va;
+ const optab_pattern *b = (const optab_pattern *)vb;
+ return a->sort_num - b->sort_num;
+}
+
+static int
+optab_kind_cmp (const void *va, const void *vb)
+{
+ const optab_def *a = (const optab_def *)va;
+ const optab_def *b = (const optab_def *)vb;
+ int diff = a->kind - b->kind;
+ if (diff == 0)
+ diff = a->op - b->op;
+ return diff;
+}
+
+static int
+optab_rcode_cmp (const void *va, const void *vb)
+{
+ const optab_def *a = (const optab_def *)va;
+ const optab_def *b = (const optab_def *)vb;
+ return a->rcode - b->rcode;
+}
+
+static const char *header_file_name = "init-opinit.h";
+static const char *source_file_name = "init-opinit.c";
+
+static bool
+handle_arg (const char *arg)
+{
+ switch (arg[1])
+ {
+ case 'h':
+ header_file_name = &arg[2];
+ return true;
+ case 'c':
+ source_file_name = &arg[2];
+ return true;
+ default:
+ return false;
+ }
+}
+
+static FILE *
+open_outfile (const char *file_name)
+{
+ FILE *f = fopen (file_name, "w");
+ if (!f)
+ fatal ("cannot open file %s: %s", file_name, xstrerror (errno));
+ fprintf (f,
+ "/* Generated automatically by the program `genopinit'\n"
+ " from the machine description file `md'. */\n\n");
+ return f;
+}
+
+int
+main (int argc, const char **argv)
+{
+ FILE *h_file, *s_file;
+ unsigned int i, j, n, last_kind[5];
+ optab_pattern *p;
+
+ progname = "genopinit";
+
+ if (NUM_OPTABS > 0xffff || MAX_MACHINE_MODE >= 0xff)
+ fatal ("genopinit range assumptions invalid");
+
+ if (!init_rtx_reader_args_cb (argc, argv, handle_arg))
+ return (FATAL_EXIT_CODE);
+
+ h_file = open_outfile (header_file_name);
+ s_file = open_outfile (source_file_name);
+
+ /* Read the machine description. */
+ md_rtx_info info;
+ while (read_md_rtx (&info))
+ switch (GET_CODE (info.def))
+ {
+ case DEFINE_INSN:
+ case DEFINE_EXPAND:
+ gen_insn (&info);
+ break;
+
+ default:
+ break;
+ }
+
+ /* Sort the collected patterns. */
+ patterns.qsort (pattern_cmp);
+
+ /* Now that we've handled the "extra" patterns, eliminate them from
+ the optabs array. That way they don't get in the way below. */
+ n = num_optabs;
+ for (i = 0; i < n; )
+ if (optabs[i].base == NULL)
+ optabs[i] = optabs[--n];
+ else
+ ++i;
+
+ /* Sort the (real) optabs. Better than forcing the optabs.def file to
+ remain sorted by kind. We also scrogged any real ordering with the
+ purging of the X patterns above. */
+ qsort (optabs, n, sizeof (optab_def), optab_kind_cmp);
+
+ fprintf (h_file, "#ifndef GCC_INSN_OPINIT_H\n");
+ fprintf (h_file, "#define GCC_INSN_OPINIT_H 1\n");
+
+ /* Emit the optab enumeration for the header file. */
+ fprintf (h_file, "enum optab_tag {\n");
+ for (i = j = 0; i < n; ++i)
+ {
+ optabs[i].op = i;
+ fprintf (h_file, " %s,\n", optabs[i].name);
+ if (optabs[i].kind != j)
+ last_kind[j++] = i - 1;
+ }
+ fprintf (h_file, " FIRST_CONV_OPTAB = %s,\n", optabs[last_kind[0]+1].name);
+ fprintf (h_file, " LAST_CONVLIB_OPTAB = %s,\n", optabs[last_kind[1]].name);
+ fprintf (h_file, " LAST_CONV_OPTAB = %s,\n", optabs[last_kind[2]].name);
+ fprintf (h_file, " FIRST_NORM_OPTAB = %s,\n", optabs[last_kind[2]+1].name);
+ fprintf (h_file, " LAST_NORMLIB_OPTAB = %s,\n", optabs[last_kind[3]].name);
+ fprintf (h_file, " LAST_NORM_OPTAB = %s\n", optabs[i-1].name);
+ fprintf (h_file, "};\n\n");
+
+ fprintf (h_file, "#define NUM_OPTABS %u\n", n);
+ fprintf (h_file, "#define NUM_CONVLIB_OPTABS %u\n",
+ last_kind[1] - last_kind[0]);
+ fprintf (h_file, "#define NUM_NORMLIB_OPTABS %u\n",
+ last_kind[3] - last_kind[2]);
+ fprintf (h_file, "#define NUM_OPTAB_PATTERNS %u\n",
+ (unsigned) patterns.length ());
+
+ fprintf (h_file,
+ "typedef enum optab_tag optab;\n"
+ "typedef enum optab_tag convert_optab;\n"
+ "typedef enum optab_tag direct_optab;\n"
+ "\n"
+ "struct optab_libcall_d\n"
+ "{\n"
+ " char libcall_suffix;\n"
+ " const char *libcall_basename;\n"
+ " void (*libcall_gen) (optab, const char *name,\n"
+ " char suffix, machine_mode);\n"
+ "};\n"
+ "\n"
+ "struct convert_optab_libcall_d\n"
+ "{\n"
+ " const char *libcall_basename;\n"
+ " void (*libcall_gen) (convert_optab, const char *name,\n"
+ " machine_mode, machine_mode);\n"
+ "};\n"
+ "\n"
+ "/* Given an enum insn_code, access the function to construct\n"
+ " the body of that kind of insn. */\n"
+ "#define GEN_FCN(CODE) (insn_data[CODE].genfun)\n"
+ "\n"
+ "#ifdef NUM_RTX_CODE\n"
+ "/* Contains the optab used for each rtx code, and vice-versa. */\n"
+ "extern const optab code_to_optab_[NUM_RTX_CODE];\n"
+ "extern const enum rtx_code optab_to_code_[NUM_OPTABS];\n"
+ "\n"
+ "static inline optab\n"
+ "code_to_optab (enum rtx_code code)\n"
+ "{\n"
+ " return code_to_optab_[code];\n"
+ "}\n"
+ "\n"
+ "static inline enum rtx_code\n"
+ "optab_to_code (optab op)\n"
+ "{\n"
+ " return optab_to_code_[op];\n"
+ "}\n"
+ "#endif\n"
+ "\n"
+ "extern const struct convert_optab_libcall_d convlib_def[NUM_CONVLIB_OPTABS];\n"
+ "extern const struct optab_libcall_d normlib_def[NUM_NORMLIB_OPTABS];\n"
+ "\n"
+ "/* Returns the active icode for the given (encoded) optab. */\n"
+ "extern enum insn_code raw_optab_handler (unsigned);\n"
+ "extern bool swap_optab_enable (optab, machine_mode, bool);\n"
+ "\n"
+ "/* Target-dependent globals. */\n"
+ "struct target_optabs {\n"
+ " /* Patterns that are used by optabs that are enabled for this target. */\n"
+ " bool pat_enable[NUM_OPTAB_PATTERNS];\n"
+ "};\n"
+ "extern void init_all_optabs (struct target_optabs *);\n"
+ "\n"
+ "extern struct target_optabs default_target_optabs;\n"
+ "extern struct target_optabs *this_fn_optabs;\n"
+ "#if SWITCHABLE_TARGET\n"
+ "extern struct target_optabs *this_target_optabs;\n"
+ "#else\n"
+ "#define this_target_optabs (&default_target_optabs)\n"
+ "#endif\n");
+
+ fprintf (s_file,
+ "#include \"config.h\"\n"
+ "#include \"system.h\"\n"
+ "#include \"coretypes.h\"\n"
+ "#include \"backend.h\"\n"
+ "#include \"predict.h\"\n"
+ "#include \"tree.h\"\n"
+ "#include \"rtl.h\"\n"
+ "#include \"alias.h\"\n"
+ "#include \"varasm.h\"\n"
+ "#include \"stor-layout.h\"\n"
+ "#include \"calls.h\"\n"
+ "#include \"memmodel.h\"\n"
+ "#include \"tm_p.h\"\n"
+ "#include \"flags.h\"\n"
+ "#include \"insn-config.h\"\n"
+ "#include \"expmed.h\"\n"
+ "#include \"dojump.h\"\n"
+ "#include \"explow.h\"\n"
+ "#include \"emit-rtl.h\"\n"
+ "#include \"stmt.h\"\n"
+ "#include \"expr.h\"\n"
+ "#include \"insn-codes.h\"\n"
+ "#include \"optabs.h\"\n"
+ "\n"
+ "struct optab_pat {\n"
+ " unsigned scode;\n"
+ " enum insn_code icode;\n"
+ "};\n\n");
+
+ fprintf (s_file,
+ "static const struct optab_pat pats[NUM_OPTAB_PATTERNS] = {\n");
+ for (i = 0; patterns.iterate (i, &p); ++i)
+ fprintf (s_file, " { %#08x, CODE_FOR_%s },\n", p->sort_num, p->name);
+ fprintf (s_file, "};\n\n");
+
+ fprintf (s_file, "void\ninit_all_optabs (struct target_optabs *optabs)\n{\n");
+ fprintf (s_file, " bool *ena = optabs->pat_enable;\n");
+ for (i = 0; patterns.iterate (i, &p); ++i)
+ fprintf (s_file, " ena[%u] = HAVE_%s;\n", i, p->name);
+ fprintf (s_file, "}\n\n");
+
+ /* Perform a binary search on a pre-encoded optab+mode*2. */
+ /* ??? Perhaps even better to generate a minimal perfect hash.
+ Using gperf directly is awkward since it's so geared to working
+ with strings. Plus we have no visibility into the ordering of
+ the hash entries, which complicates the pat_enable array. */
+ fprintf (s_file,
+ "static int\n"
+ "lookup_handler (unsigned scode)\n"
+ "{\n"
+ " int l = 0, h = ARRAY_SIZE (pats), m;\n"
+ " while (h > l)\n"
+ " {\n"
+ " m = (h + l) / 2;\n"
+ " if (scode == pats[m].scode)\n"
+ " return m;\n"
+ " else if (scode < pats[m].scode)\n"
+ " h = m;\n"
+ " else\n"
+ " l = m + 1;\n"
+ " }\n"
+ " return -1;\n"
+ "}\n\n");
+
+ fprintf (s_file,
+ "enum insn_code\n"
+ "raw_optab_handler (unsigned scode)\n"
+ "{\n"
+ " int i = lookup_handler (scode);\n"
+ " return (i >= 0 && this_fn_optabs->pat_enable[i]\n"
+ " ? pats[i].icode : CODE_FOR_nothing);\n"
+ "}\n\n");
+
+ fprintf (s_file,
+ "bool\n"
+ "swap_optab_enable (optab op, machine_mode m, bool set)\n"
+ "{\n"
+ " unsigned scode = (op << 16) | m;\n"
+ " int i = lookup_handler (scode);\n"
+ " if (i >= 0)\n"
+ " {\n"
+ " bool ret = this_fn_optabs->pat_enable[i];\n"
+ " this_fn_optabs->pat_enable[i] = set;\n"
+ " return ret;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " gcc_assert (!set);\n"
+ " return false;\n"
+ " }\n"
+ "}\n\n");
+
+ /* C++ (even G++) does not support (non-trivial) designated initializers.
+ To work around that, generate these arrays programatically rather than
+ by our traditional multiple inclusion of def files. */
+
+ fprintf (s_file,
+ "const struct convert_optab_libcall_d "
+ "convlib_def[NUM_CONVLIB_OPTABS] = {\n");
+ for (i = last_kind[0] + 1; i <= last_kind[1]; ++i)
+ fprintf (s_file, " { %s, %s },\n", optabs[i].base, optabs[i].libcall);
+ fprintf (s_file, "};\n\n");
+
+ fprintf (s_file,
+ "const struct optab_libcall_d "
+ "normlib_def[NUM_NORMLIB_OPTABS] = {\n");
+ for (i = last_kind[2] + 1; i <= last_kind[3]; ++i)
+ fprintf (s_file, " { %s, %s, %s },\n",
+ optabs[i].suffix, optabs[i].base, optabs[i].libcall);
+ fprintf (s_file, "};\n\n");
+
+ fprintf (s_file, "enum rtx_code const optab_to_code_[NUM_OPTABS] = {\n");
+ for (i = 0; i < n; ++i)
+ fprintf (s_file, " %s,\n", rtx_upname[optabs[i].fcode]);
+ fprintf (s_file, "};\n\n");
+
+ qsort (optabs, n, sizeof (optab_def), optab_rcode_cmp);
+
+ fprintf (s_file, "const optab code_to_optab_[NUM_RTX_CODE] = {\n");
+ for (j = 0; optabs[j].rcode == UNKNOWN; ++j)
+ continue;
+ for (i = 0; i < NON_GENERATOR_NUM_RTX_CODE; ++i)
+ {
+ if (j < n && optabs[j].rcode == i)
+ fprintf (s_file, " %s,\n", optabs[j++].name);
+ else
+ fprintf (s_file, " unknown_optab,\n");
+ }
+ fprintf (s_file, "};\n\n");
+
+ fprintf (h_file, "#endif\n");
+ return (fclose (h_file) == 0 && fclose (s_file) == 0
+ ? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE);
+}