[A fair bit later than promised, sorry...] Mikhail posted a patch to make genflags generate the default HAVE_foo and gen_foo definitions that have recently been added to defaults.h:
https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00723.html I agree it'd be a good idea to generate this kind of thing automatically, but I think we should take the opportunity to move the interface to the target structure. I.e.: HAVE_foo -> targetm.have_foo () gen_foo -> targetm.gen_foo () This should move us closer to the pipedream goal of supporting multiple targets at once. It should also mean that only the target code depends on insn-flags.h. The patch just moves return and simple_return as an example. I have more locally (in order to test other code paths), but they're just an obvious extension of this one. The patch relies on the hashing changes in: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg01066.html https://gcc.gnu.org/ml/gcc-patches/2015-06/msg01564.html and on this trivial patch: https://gcc.gnu.org/ml/gcc-patches/2015-06/msg01604.html It seems a bit heavyweight when you just look at these two instructions, but I think it'll be a saving in the end. Bootstrapped & regression-tested on x86_64-linux-gnu. Also tested via config-list.mk. OK to install? Thanks, Richard gcc/ * Makefile.in (TARGET_DEF): Add target-insns.def. (.PRECIOUS, simple_rtl_generated_h): Add insn-target-def.h. (build/gentarget-def.o): New rule. (genprogrtl): Add target-def. * target-insns.def, gentarget-def.c: New files. * target.def: Add targetm.have_* and targetm.gen_* hooks, based on the contents of target-insns.def. * defaults.h (HAVE_simple_return, gen_simple_return): Delete. (HAVE_return, gen_return): Delete. * target-def.h: Include insn-target-def.h. * cfgrtl.c (force_nonfallthru_and_redirect): Use targetm interface instead of direct calls. Rely on them to do the appropriate assertions. * function.c (gen_return_pattern): Likewise. Return an rtx_insn *. (convert_jumps_to_returns): Use targetm interface instead of direct calls. (thread_prologue_and_epilogue_insns): Likewise. * reorg.c (find_end_label, dbr_schedule): Likewise. * shrink-wrap.h (SHRINK_WRAPPING_ENABLED): Likewise. * shrink-wrap.c (convert_to_simple_return): Likewise. (try_shrink_wrapping): Use SHRINK_WRAPPING_ENABLED. Index: gcc/Makefile.in =================================================================== --- gcc/Makefile.in 2015-06-22 14:03:10.985503368 +0100 +++ gcc/Makefile.in 2015-06-22 14:04:26.689971484 +0100 @@ -866,7 +866,7 @@ DUMPFILE_H = $(srcdir)/../libcpp/include VEC_H = vec.h statistics.h $(GGC_H) HASH_TABLE_H = $(HASHTAB_H) hash-table.h EXCEPT_H = except.h $(HASHTAB_H) -TARGET_DEF = target.def target-hooks-macros.h +TARGET_DEF = target.def target-hooks-macros.h target-insns.def C_TARGET_DEF = c-family/c-target.def target-hooks-macros.h COMMON_TARGET_DEF = common/common-target.def target-hooks-macros.h TARGET_H = $(TM_H) target.h $(TARGET_DEF) insn-modes.h insn-codes.h @@ -2078,7 +2078,8 @@ $(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-latencytab.c insn-preds.c gimple-match.c generic-match.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 @@ -2099,7 +2100,7 @@ s-mddeps: $(md_file) $(MD_INCLUDES) buil # the target file. simple_rtl_generated_h = insn-attr.h insn-attr-common.h insn-codes.h \ - insn-config.h insn-flags.h + insn-config.h insn-flags.h insn-target-def.h simple_rtl_generated_c = insn-automata.c insn-emit.c \ insn-extract.c insn-output.c \ @@ -2498,6 +2499,9 @@ build/genextract.o : genextract.c $(RTL_ $(SYSTEM_H) coretypes.h $(GTM_H) errors.h $(READ_MD_H) gensupport.h build/genflags.o : genflags.c $(RTL_BASE_H) $(OBSTACK_H) $(BCONFIG_H) \ $(SYSTEM_H) coretypes.h $(GTM_H) errors.h $(READ_MD_H) gensupport.h +build/gentarget-def.o : gentarget-def.c $(BCONFIG_H) $(SYSTEM_H) \ + coretypes.h $(GTM_H) $(RTL_BASE_H) errors.h $(READ_MD_H) gensupport.h \ + $(HASH_TABLE_H) target-insns.def build/gengenrtl.o : gengenrtl.c $(BCONFIG_H) $(SYSTEM_H) rtl.def # The gengtype generator program is special: Two versions are built. @@ -2562,7 +2566,7 @@ build/genmatch.o : genmatch.c $(BCONFIG_ # All these programs use the RTL reader ($(BUILD_RTL)). genprogrtl = attr attr-common attrtab automata codes conditions config emit \ - extract flags opinit output peep preds recog mddump + extract flags mddump opinit output peep preds recog target-def $(genprogrtl:%=build/gen%$(build_exeext)): $(BUILD_RTL) # All these programs use the MD reader ($(BUILD_MD)). Index: gcc/target-insns.def =================================================================== --- /dev/null 2015-06-22 13:54:06.971314091 +0100 +++ gcc/target-insns.def 2015-06-22 14:04:26.690971419 +0100 @@ -0,0 +1,34 @@ +/* Target instruction definitions. + Copyright (C) 2015 Free Software Foundation, Inc. + + This program 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. + + This program 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 this program; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* This file has one entry for each public pattern name that the target + can provide. It is only used if no distinction between operand modes + is necessary. If separate patterns are needed for different modes + (so as to distinguish addition of QImode values from addition of + HImode values, for example) then an optab should be used instead. + + Each entry has the form: + + DEF_TARGET_INSN (name, prototype) + + where NAME is the name of the pattern and PROTOTYPE is its C prototype. + The prototype should use parameter names of the form "x0", "x1", etc. + Patterns that take no operands should have a prototype "(void)". + + Instructions should be documented in md.texi rather than here. */ +DEF_TARGET_INSN (return, (void)) +DEF_TARGET_INSN (simple_return, (void)) Index: gcc/gentarget-def.c =================================================================== --- /dev/null 2015-06-22 13:54:06.971314091 +0100 +++ gcc/gentarget-def.c 2015-06-22 14:04:26.689971484 +0100 @@ -0,0 +1,265 @@ +/* Generate insn-target-def.h, an automatically-generated part of targetm. + Copyright (C) 1987-2015 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; + +/* 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; + for (const char *p = prototype; *p; ++p) + if (*p == 'x' && ISDIGIT (p[1])) + { + /* This should be a parameter name of the form "x<OPNO>". + That doesn't contribute to the suffix, so skip ahead and + process the following character. */ + char *endptr; + if (strtol (p + 1, &endptr, 10) != opno + || (*endptr != ',' && *endptr != ')')) + { + error ("invalid prototype for '%s'", name); + exit (FATAL_EXIT_CODE); + } + opno += 1; + p = endptr; + 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)) + { + 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 "); + print_c_condition (test); + printf (";\n"); + printf ("}\n"); + } + have_name = entry; + } + printf ("\nstatic rtx_insn *\n"); + printf ("target_gen_%s %s\n", name, prototype); + printf ("{\n"); + if (truth < 0) + printf (" gcc_checking_assert (targetm.have_%s ());\n", name); + printf (" return insnify (gen_%s (", name); + for (i = 0; i < opno; ++i) + printf ("%sx%d", i == 0 ? "" : ", ", 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); + const char *p = prototype; + while (*p) + { + if (p[0] == 'x' && ISDIGIT (p[1])) + { + char *endptr; + strtol (p + 1, &endptr, 10); + p = endptr; + } + else + 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); +} + +int +main (int argc, char **argv) +{ + int insn_code_number = 0; + + 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 *>; + + while (1) + { + int line_no; + rtx desc = read_md_rtx (&line_no, &insn_code_number); + if (desc == NULL) + break; + if (GET_CODE (desc) == DEFINE_INSN || GET_CODE (desc) == DEFINE_EXPAND) + { + const char *name = XSTR (desc, 0); + if (name[0] != 0 && name[0] != '*') + { + hashval_t hash = htab_hash_string (name); + rtx *slot = insns->find_slot_with_hash (name, hash, INSERT); + if (*slot) + { + message_with_line (line_no, "duplicate definition of '%s'", + name); + have_error = 1; + } + else + *slot = desc; + } + } + } + + 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);\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; +} Index: gcc/target.def =================================================================== --- gcc/target.def 2015-06-22 14:03:10.985503368 +0100 +++ gcc/target.def 2015-06-22 14:04:26.690971419 +0100 @@ -5864,6 +5864,19 @@ DEFHOOK HOOK_VECTOR_END (mode_switching) +#undef HOOK_PREFIX +#define HOOK_PREFIX "TARGET_" + +#define DEF_TARGET_INSN(NAME, PROTO) \ + DEFHOOK_UNDOC (have_##NAME, "", bool, (void), false) +#include "target-insns.def" +#undef DEF_TARGET_INSN + +#define DEF_TARGET_INSN(NAME, PROTO) \ + DEFHOOK_UNDOC (gen_##NAME, "", rtx_insn *, PROTO, NULL) +#include "target-insns.def" +#undef DEF_TARGET_INSN + /* Close the 'struct gcc_target' definition. */ HOOK_VECTOR_END (C90_EMPTY_HACK) Index: gcc/defaults.h =================================================================== --- gcc/defaults.h 2015-06-22 14:03:10.985503368 +0100 +++ gcc/defaults.h 2015-06-22 14:04:26.691971355 +0100 @@ -1426,26 +1426,6 @@ #define STACK_CHECK_MAX_VAR_SIZE (STACK_ #define TARGET_VTABLE_USES_DESCRIPTORS 0 #endif -#ifndef HAVE_simple_return -#define HAVE_simple_return 0 -static inline rtx -gen_simple_return () -{ - gcc_unreachable (); - return NULL; -} -#endif - -#ifndef HAVE_return -#define HAVE_return 0 -static inline rtx -gen_return () -{ - gcc_unreachable (); - return NULL; -} -#endif - #ifndef HAVE_epilogue #define HAVE_epilogue 0 static inline rtx Index: gcc/target-def.h =================================================================== --- gcc/target-def.h 2015-06-22 14:03:10.985503368 +0100 +++ gcc/target-def.h 2015-06-22 14:04:26.689971484 +0100 @@ -107,3 +107,4 @@ #define TARGET_FUNCTION_INCOMING_ARG TAR #include "hooks.h" #include "targhooks.h" +#include "insn-target-def.h" Index: gcc/cfgrtl.c =================================================================== --- gcc/cfgrtl.c 2015-06-22 14:02:23.724223518 +0100 +++ gcc/cfgrtl.c 2015-06-22 14:04:26.693971225 +0100 @@ -1695,19 +1695,12 @@ force_nonfallthru_and_redirect (edge e, if (target == EXIT_BLOCK_PTR_FOR_FN (cfun)) { if (jump_label == ret_rtx) - { - if (!HAVE_return) - gcc_unreachable (); - - emit_jump_insn_after_setloc (gen_return (), BB_END (jump_block), loc); - } + emit_jump_insn_after_setloc (targetm.gen_return (), + BB_END (jump_block), loc); else { gcc_assert (jump_label == simple_return_rtx); - if (!HAVE_simple_return) - gcc_unreachable (); - - emit_jump_insn_after_setloc (gen_simple_return (), + emit_jump_insn_after_setloc (targetm.gen_simple_return (), BB_END (jump_block), loc); } set_return_jump_label (BB_END (jump_block)); Index: gcc/function.c =================================================================== --- gcc/function.c 2015-06-22 14:04:03.369476746 +0100 +++ gcc/function.c 2015-06-22 14:04:26.692971290 +0100 @@ -5657,13 +5657,12 @@ emit_use_return_register_into_block (bas /* Create a return pattern, either simple_return or return, depending on simple_p. */ -static rtx +static rtx_insn * gen_return_pattern (bool simple_p) { - if (!HAVE_simple_return) - gcc_assert (!simple_p); - - return simple_p ? gen_simple_return () : gen_return (); + return (simple_p + ? targetm.gen_simple_return () + : targetm.gen_return ()); } /* Insert an appropriate return pattern at the end of block BB. This @@ -5769,7 +5768,7 @@ convert_jumps_to_returns (basic_block la dest = ret_rtx; if (!redirect_jump (as_a <rtx_jump_insn *> (jump), dest, 0)) { - if (HAVE_simple_return && simple_p) + if (targetm.have_simple_return () && simple_p) { if (dump_file) fprintf (dump_file, @@ -5790,7 +5789,7 @@ convert_jumps_to_returns (basic_block la } else { - if (HAVE_simple_return && simple_p) + if (targetm.have_simple_return () && simple_p) { if (dump_file) fprintf (dump_file, @@ -5981,12 +5980,12 @@ thread_prologue_and_epilogue_insns (void exit_fallthru_edge = find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds); - if (HAVE_simple_return && entry_edge != orig_entry_edge) + if (targetm.have_simple_return () && entry_edge != orig_entry_edge) exit_fallthru_edge = get_unconverted_simple_return (exit_fallthru_edge, bb_flags, &unconverted_simple_returns, &returnjump); - if (HAVE_return) + if (targetm.have_return ()) { if (exit_fallthru_edge == NULL) goto epilogue_done; @@ -6007,7 +6006,8 @@ thread_prologue_and_epilogue_insns (void /* Emitting the return may add a basic block. Fix bb_flags for the added block. */ - if (HAVE_simple_return && last_bb != exit_fallthru_edge->src) + if (targetm.have_simple_return () + && last_bb != exit_fallthru_edge->src) bitmap_set_bit (&bb_flags, last_bb->index); goto epilogue_done; @@ -6123,7 +6123,7 @@ thread_prologue_and_epilogue_insns (void } } - if (HAVE_simple_return) + if (targetm.have_simple_return ()) convert_to_simple_return (entry_edge, orig_entry_edge, bb_flags, returnjump, unconverted_simple_returns); @@ -6139,8 +6139,9 @@ thread_prologue_and_epilogue_insns (void if (!CALL_P (insn) || ! SIBLING_CALL_P (insn) - || (HAVE_simple_return && (entry_edge != orig_entry_edge - && !bitmap_bit_p (&bb_flags, bb->index)))) + || (targetm.have_simple_return () + && entry_edge != orig_entry_edge + && !bitmap_bit_p (&bb_flags, bb->index))) { ei_next (&ei); continue; Index: gcc/reorg.c =================================================================== --- gcc/reorg.c 2015-06-22 14:03:10.985503368 +0100 +++ gcc/reorg.c 2015-06-22 14:04:26.692971290 +0100 @@ -473,7 +473,7 @@ find_end_label (rtx kind) } else { - if (HAVE_epilogue && ! HAVE_return) + if (HAVE_epilogue && ! targetm.have_return ()) /* The RETURN insn has its delay slot filled so we cannot emit the label just before it. Since we already have an epilogue and cannot emit a new RETURN, we cannot @@ -483,10 +483,10 @@ find_end_label (rtx kind) /* Otherwise, make a new label and emit a RETURN and BARRIER, if needed. */ emit_label (label); - if (HAVE_return) + if (targetm.have_return ()) { /* The return we make may have delay slots too. */ - rtx pat = gen_return (); + rtx_insn *pat = targetm.gen_return (); rtx_insn *insn = emit_jump_insn (pat); set_return_jump_label (insn); emit_barrier (); @@ -3815,8 +3815,9 @@ dbr_schedule (rtx_insn *first) delete_related_insns (function_simple_return_label); need_return_insns = false; - need_return_insns |= HAVE_return && function_return_label != 0; - need_return_insns |= HAVE_simple_return && function_simple_return_label != 0; + need_return_insns |= targetm.have_return () && function_return_label != 0; + need_return_insns |= (targetm.have_simple_return () + && function_simple_return_label != 0); if (need_return_insns) make_return_insns (first); Index: gcc/shrink-wrap.h =================================================================== --- gcc/shrink-wrap.h 2015-06-22 14:03:10.985503368 +0100 +++ gcc/shrink-wrap.h 2015-06-22 14:04:26.692971290 +0100 @@ -36,7 +36,8 @@ extern void convert_to_simple_return (ed bitmap_head bb_flags, rtx_insn *returnjump, vec<edge> unconverted_simple_returns); -#define SHRINK_WRAPPING_ENABLED (flag_shrink_wrap && HAVE_simple_return) +#define SHRINK_WRAPPING_ENABLED \ + (flag_shrink_wrap && targetm.have_simple_return ()) #endif /* GCC_SHRINK_WRAP_H */ Index: gcc/shrink-wrap.c =================================================================== --- gcc/shrink-wrap.c 2015-06-22 14:03:10.985503368 +0100 +++ gcc/shrink-wrap.c 2015-06-22 14:04:26.692971290 +0100 @@ -541,7 +541,7 @@ try_shrink_wrapping (edge *entry_edge, e break; } - if (flag_shrink_wrap && HAVE_simple_return + if (SHRINK_WRAPPING_ENABLED && (targetm.profile_before_prologue () || !crtl->profile) && nonempty_prologue && !crtl->calls_eh_return) { @@ -1004,8 +1004,8 @@ convert_to_simple_return (edge entry_edg bb = create_basic_block (NULL, NULL, exit_pred); BB_COPY_PARTITION (bb, e->src); - rtx_jump_insn *start = emit_jump_insn_after (gen_simple_return (), - BB_END (bb)); + rtx_insn *ret = targetm.gen_simple_return (); + rtx_jump_insn *start = emit_jump_insn_after (ret, BB_END (bb)); JUMP_LABEL (start) = simple_return_rtx; emit_barrier_after (start);