Mercurial > hg > CbC > CbC_gcc
diff gcc/gentarget-def.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gcc/gentarget-def.c Fri Oct 27 22:46:09 2017 +0900 @@ -0,0 +1,338 @@ +/* Generate insn-target-def.h, an automatically-generated part of targetm. + Copyright (C) 1987-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 "read-md.h" +#include "gensupport.h" +#include "hash-table.h" + +/* This class hashes define_insns and define_expands by name. */ +struct insn_hasher : nofree_ptr_hash <rtx_def> +{ + typedef rtx value_type; + typedef const char *compare_type; + + static inline hashval_t hash (rtx); + static inline bool equal (rtx, const char *); +}; + +hashval_t +insn_hasher::hash (rtx x) +{ + return htab_hash_string (XSTR (x, 0)); +} + +bool +insn_hasher::equal (rtx x, const char *y) +{ + return strcmp (XSTR (x, 0), y) == 0; +} + +/* All define_insns and define_expands, hashed by name. */ +static hash_table <insn_hasher> *insns; + +/* Records the prototype suffix X for each invalid_X stub that has been + generated. */ +static hash_table <nofree_string_hash> *stubs; + +/* Records which C conditions have been wrapped in functions, as a mapping + from the C condition to the function name. */ +static hash_map <nofree_string_hash, const char *> *have_funcs; + +/* Return true if the part of the prototype at P is for an argument + name. If so, point *END_OUT to the first character after the name. + If OPNO_OUT is nonnull, set *OPNO_OUT to the number of the associated + operand. If REQUIRED_OUT is nonnull, set *REQUIRED_OUT to whether the + .md pattern is required to match the operand. */ + +static bool +parse_argument (const char *p, const char **end_out, + unsigned int *opno_out = 0, + bool *required_out = 0) +{ + while (ISSPACE (*p)) + p++; + if (p[0] == 'x' && ISDIGIT (p[1])) + { + p += 1; + if (required_out) + *required_out = true; + } + else if (p[0] == 'o' && p[1] == 'p' && p[2] == 't' && ISDIGIT (p[3])) + { + p += 3; + if (required_out) + *required_out = false; + } + else + return false; + + char *endptr; + unsigned int opno = strtol (p, &endptr, 10); + if (opno_out) + *opno_out = opno; + *end_out = endptr; + return true; +} + + +/* Output hook definitions for pattern NAME, which has target-insns.def + prototype PROTOTYPE. */ + +static void +def_target_insn (const char *name, const char *prototype) +{ + /* Get an upper-case form of NAME. */ + unsigned int i; + char *upper_name = XALLOCAVEC (char, strlen (name) + 1); + for (i = 0; name[i]; ++i) + upper_name[i] = TOUPPER (name[i]); + upper_name[i] = 0; + + /* Check that the prototype is valid and concatenate the types + together to get a suffix. */ + char *suffix = XALLOCAVEC (char, strlen (prototype) + 1); + i = 0; + unsigned int opno = 0; + unsigned int required_ops = 0; + unsigned int this_opno; + bool required_p; + for (const char *p = prototype; *p; ++p) + if (parse_argument (p, &p, &this_opno, &required_p)) + { + if (this_opno != opno || (*p != ',' && *p != ')')) + { + error ("invalid prototype for '%s'", name); + exit (FATAL_EXIT_CODE); + } + if (required_p && required_ops < opno) + { + error ("prototype for '%s' has required operands after" + " optional operands", name); + exit (FATAL_EXIT_CODE); + } + opno += 1; + if (required_p) + required_ops = opno; + /* Skip over ')'s. */ + if (*p == ',') + suffix[i++] = '_'; + } + else if (*p == ')' || *p == ',') + { + /* We found the end of a parameter without finding a + parameter name. */ + if (strcmp (prototype, "(void)") != 0) + { + error ("argument %d of '%s' did not have the expected name", + opno, name); + exit (FATAL_EXIT_CODE); + } + } + else if (*p != '(' && !ISSPACE (*p)) + suffix[i++] = *p; + suffix[i] = 0; + + /* See whether we have an implementation of this pattern. */ + hashval_t hash = htab_hash_string (name); + int truth = 0; + const char *have_name = name; + if (rtx insn = insns->find_with_hash (name, hash)) + { + pattern_stats stats; + get_pattern_stats (&stats, XVEC (insn, 1)); + unsigned int actual_ops = stats.num_generator_args; + if (opno == required_ops && opno != actual_ops) + error_at (get_file_location (insn), + "'%s' must have %d operands (excluding match_dups)", + name, required_ops); + else if (actual_ops < required_ops) + error_at (get_file_location (insn), + "'%s' must have at least %d operands (excluding match_dups)", + name, required_ops); + else if (actual_ops > opno) + error_at (get_file_location (insn), + "'%s' must have no more than %d operands" + " (excluding match_dups)", name, opno); + + const char *test = XSTR (insn, 2); + truth = maybe_eval_c_test (test); + gcc_assert (truth != 0); + if (truth < 0) + { + /* Try to reuse an existing function that performs the same test. */ + bool existed; + const char *&entry = have_funcs->get_or_insert (test, &existed); + if (!existed) + { + entry = name; + printf ("\nstatic bool\n"); + printf ("target_have_%s (void)\n", name); + printf ("{\n"); + printf (" return "); + rtx_reader_ptr->print_c_condition (test); + printf (";\n"); + printf ("}\n"); + } + have_name = entry; + } + printf ("\nstatic rtx_insn *\n"); + printf ("target_gen_%s ", name); + /* Print the prototype with the argument names after ACTUAL_OPS + removed. */ + const char *p = prototype, *end; + while (*p) + if (parse_argument (p, &end, &this_opno) && this_opno >= actual_ops) + p = end; + else + fputc (*p++, stdout); + + printf ("\n{\n"); + if (truth < 0) + printf (" gcc_checking_assert (targetm.have_%s ());\n", name); + printf (" return insnify (gen_%s (", name); + for (i = 0; i < actual_ops; ++i) + printf ("%s%s%d", i == 0 ? "" : ", ", + i < required_ops ? "x" : "opt", i); + printf ("));\n"); + printf ("}\n"); + } + else + { + const char **slot = stubs->find_slot (suffix, INSERT); + if (!*slot) + { + *slot = xstrdup (suffix); + printf ("\nstatic rtx_insn *\n"); + printf ("invalid_%s ", suffix); + /* Print the prototype with the argument names removed. */ + const char *p = prototype; + while (*p) + if (!parse_argument (p, &p)) + fputc (*p++, stdout); + printf ("\n{\n"); + printf (" gcc_unreachable ();\n"); + printf ("}\n"); + } + } + printf ("\n#undef TARGET_HAVE_%s\n", upper_name); + printf ("#define TARGET_HAVE_%s ", upper_name); + if (truth == 0) + printf ("hook_bool_void_false\n"); + else if (truth == 1) + printf ("hook_bool_void_true\n"); + else + printf ("target_have_%s\n", have_name); + + printf ("#undef TARGET_GEN_%s\n", upper_name); + printf ("#define TARGET_GEN_%s ", upper_name); + if (truth == 0) + printf ("invalid_%s\n", suffix); + else + printf ("target_gen_%s\n", name); + + printf ("#undef TARGET_CODE_FOR_%s\n", upper_name); + printf ("#define TARGET_CODE_FOR_%s ", upper_name); + if (truth == 0) + printf ("CODE_FOR_nothing\n"); + else + printf ("CODE_FOR_%s\n", name); +} + +/* Record the DEFINE_INSN or DEFINE_EXPAND described by INFO. */ + +static void +add_insn (md_rtx_info *info) +{ + rtx def = info->def; + const char *name = XSTR (def, 0); + if (name[0] == 0 || name[0] == '*') + return; + + hashval_t hash = htab_hash_string (name); + rtx *slot = insns->find_slot_with_hash (name, hash, INSERT); + if (*slot) + error_at (info->loc, "duplicate definition of '%s'", name); + else + *slot = def; +} + +int +main (int argc, const char **argv) +{ + progname = "gentarget-def"; + + if (!init_rtx_reader_args (argc, argv)) + return (FATAL_EXIT_CODE); + + insns = new hash_table <insn_hasher> (31); + stubs = new hash_table <nofree_string_hash> (31); + have_funcs = new hash_map <nofree_string_hash, const char *>; + + md_rtx_info info; + while (read_md_rtx (&info)) + switch (GET_CODE (info.def)) + { + case DEFINE_INSN: + case DEFINE_EXPAND: + add_insn (&info); + break; + + default: + break; + } + + printf ("/* Generated automatically by the program `gentarget-def'. */\n"); + printf ("#ifndef GCC_INSN_TARGET_DEF_H\n"); + printf ("#define GCC_INSN_TARGET_DEF_H\n"); + + /* Output a routine to convert an rtx to an rtx_insn sequence. + ??? At some point the gen_* functions themselves should return + rtx_insns. */ + printf ("\nstatic inline rtx_insn *\n"); + printf ("insnify (rtx x)\n"); + printf ("{\n"); + printf (" if (!x)\n"); + printf (" return NULL;\n"); + printf (" if (rtx_insn *insn = dyn_cast <rtx_insn *> (x))\n"); + printf (" return insn;\n"); + printf (" start_sequence ();\n"); + printf (" emit (x, false);\n"); + printf (" rtx_insn *res = get_insns ();\n"); + printf (" end_sequence ();\n"); + printf (" return res;\n"); + printf ("}\n"); + +#define DEF_TARGET_INSN(INSN, ARGS) \ + def_target_insn (#INSN, #ARGS); +#include "target-insns.def" +#undef DEF_TARGET_INSN + + printf ("\n#endif /* GCC_INSN_TARGET_DEF_H */\n"); + + if (have_error || ferror (stdout) || fflush (stdout) || fclose (stdout)) + return FATAL_EXIT_CODE; + + return SUCCESS_EXIT_CODE; +}