+2015-06-25 Richard Sandiford <richard.sandiford@arm.com>
+
+ * 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.
+
2015-06-25 Richard Sandiford <richard.sandiford@arm.com>
* config/aarch64/aarch64.c, config/alpha/alpha.c, config/arm/arm.c,
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
.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
# 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 \
$(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.
# 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)).
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));
#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
/* 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
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,
}
else
{
- if (HAVE_simple_return && simple_p)
+ if (targetm.have_simple_return () && simple_p)
{
if (dump_file)
fprintf (dump_file,
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;
/* 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;
}
}
- if (HAVE_simple_return)
+ if (targetm.have_simple_return ())
convert_to_simple_return (entry_edge, orig_entry_edge, bb_flags,
returnjump, unconverted_simple_returns);
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;
--- /dev/null
+/* 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;
+}
}
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
/* 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 ();
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);
break;
}
- if (flag_shrink_wrap && HAVE_simple_return
+ if (SHRINK_WRAPPING_ENABLED
&& (targetm.profile_before_prologue () || !crtl->profile)
&& nonempty_prologue && !crtl->calls_eh_return)
{
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);
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 */
#include "hooks.h"
#include "targhooks.h"
+#include "insn-target-def.h"
--- /dev/null
+/* 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))
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)