summaryrefslogtreecommitdiff
path: root/gcc/read-rtl.c
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2018-08-02 10:59:35 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2018-08-02 10:59:35 +0000
commit0016d8d91cb2880e69be74efb44367b282577977 (patch)
treec65a69b7b2e33e1f21911fa540f0ce7579294e37 /gcc/read-rtl.c
parenta451882123524de1b9b175af97a1cdd32e5f25c1 (diff)
[gen/AArch64] Generate helpers for substituting iterator values into pattern names
Given a pattern like: (define_insn "aarch64_frecpe<mode>" ...) the SVE ACLE implementation wants to generate the pattern for a particular (non-constant) mode. This patch automatically generates helpers to do that, specifically: // Return CODE_FOR_nothing on failure. insn_code maybe_code_for_aarch64_frecpe (machine_mode); // Assert that the code exists. insn_code code_for_aarch64_frecpe (machine_mode); // Return NULL_RTX on failure. rtx maybe_gen_aarch64_frecpe (machine_mode, rtx, rtx); // Assert that generation succeeds. rtx gen_aarch64_frecpe (machine_mode, rtx, rtx); Many patterns don't have sensible names when all <...>s are removed. E.g. "<optab><mode>2" would give a base name "2". The new functions therefore require explicit opt-in, which should also help to reduce code bloat. The (arbitrary) opt-in syntax I went for was to prefix the pattern name with '@', similarly to the existing '*' marker. The patch also makes config/aarch64 use the new routines in cases where they obviously apply. This was mostly straight-forward, but it seemed odd that we defined: aarch64_reload_movcp<...><P:mode> but then only used it with DImode, never SImode. If we should be using Pmode instead of DImode, then that's a simple change, but should probably be a separate patch. 2018-08-02 Richard Sandiford <richard.sandiford@arm.com> gcc/ * doc/md.texi: Expand the documentation of instruction names to mention port-local uses. Document '@' in pattern names. * read-md.h (overloaded_instance, overloaded_name): New structs. (mapping): Declare. (md_reader::handle_overloaded_name): New member function. (md_reader::get_overloads): Likewise. (md_reader::m_first_overload): New member variable. (md_reader::m_next_overload_ptr): Likewise. (md_reader::m_overloads_htab): Likewise. * read-md.c (md_reader::md_reader): Initialize m_first_overload, m_next_overload_ptr and m_overloads_htab. * read-rtl.c (iterator_group): Add "type" and "get_c_token" fields. (get_mode_token, get_code_token, get_int_token): New functions. (map_attr_string): Add an optional argument that passes back the associated iterator. (overloaded_name_hash, overloaded_name_eq_p, named_rtx_p): (md_reader::handle_overloaded_name, add_overload_instance): New functions. (apply_iterators): Handle '@' names. Report an error if '@' is used without iterators. (initialize_iterators): Initialize the new iterator_group fields. * genopinit.c (handle_overloaded_code_for) (handle_overloaded_gen): New functions. (main): Use them to print declarations of maybe_code_for_* and maybe_gen_* functions, and inline definitions of code_for_* and gen_*. * genemit.c (print_overload_arguments, print_overload_test) (handle_overloaded_code_for, handle_overloaded_gen): New functions. (main): Use it to print definitions of maybe_code_for_* and maybe_gen_* functions. * config/aarch64/aarch64.c (aarch64_split_128bit_move): Use gen_aarch64_mov{low,high}_di and gen_aarch64_movdi_{low,high} instead of explicit mode checks. (aarch64_split_simd_combine): Likewise gen_aarch64_simd_combine. (aarch64_split_simd_move): Likewise gen_aarch64_split_simd_mov. (aarch64_emit_load_exclusive): Likewise gen_aarch64_load_exclusive. (aarch64_emit_store_exclusive): Likewise gen_aarch64_store_exclusive. (aarch64_expand_compare_and_swap): Likewise gen_aarch64_compare_and_swap and gen_aarch64_compare_and_swap_lse (aarch64_gen_atomic_cas): Likewise gen_aarch64_atomic_cas. (aarch64_emit_atomic_swap): Likewise gen_aarch64_atomic_swp. (aarch64_constant_pool_reload_icode): Delete. (aarch64_secondary_reload): Use code_for_aarch64_reload_movcp instead of aarch64_constant_pool_reload_icode. Use code_for_aarch64_reload_mov instead of explicit mode checks. (rsqrte_type, get_rsqrte_type, rsqrts_type, get_rsqrts_type): Delete. (aarch64_emit_approx_sqrt): Use gen_aarch64_rsqrte instead of get_rsqrte_type and gen_aarch64_rsqrts instead of gen_rqrts_type. (recpe_type, get_recpe_type, recps_type, get_recps_type): Delete. (aarch64_emit_approx_div): Use gen_aarch64_frecpe instead of get_recpe_type and gen_aarch64_frecps instead of get_recps_type. (aarch64_atomic_load_op_code): Delete. (aarch64_emit_atomic_load_op): Likewise. (aarch64_gen_atomic_ldop): Use UNSPECV_ATOMIC_* instead of aarch64_atomic_load_op_code. Use gen_aarch64_atomic_load instead of aarch64_emit_atomic_load_op. * config/aarch64/aarch64.md (aarch64_reload_movcp<GPF_TF:mode><P:mode>) (aarch64_reload_movcp<VALL:mode><P:mode>, aarch64_reload_mov<mode>) (aarch64_movdi_<mode>low, aarch64_movdi_<mode>high) (aarch64_mov<mode>high_di, aarch64_mov<mode>low_di): Add a '@' character before the pattern name. * config/aarch64/aarch64-simd.md (aarch64_split_simd_mov<mode>) (aarch64_rsqrte<mode>, aarch64_rsqrts<mode>) (aarch64_simd_combine<mode>, aarch64_frecpe<mode>) (aarch64_frecps<mode>): Likewise. * config/aarch64/atomics.md (atomic_compare_and_swap<mode>) (aarch64_compare_and_swap<mode>, aarch64_compare_and_swap<mode>_lse) (aarch64_load_exclusive<mode>, aarch64_store_exclusive<mode>) (aarch64_atomic_swp<mode>, aarch64_atomic_cas<mode>) (aarch64_atomic_load<atomic_ldop><mode>): Likewise. From-SVN: r263251
Diffstat (limited to 'gcc/read-rtl.c')
-rw-r--r--gcc/read-rtl.c233
1 files changed, 230 insertions, 3 deletions
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 341b1858a12..723c3e174b5 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -72,6 +72,9 @@ struct iterator_group {
iterators. */
htab_t attrs, iterators;
+ /* The C++ type of the iterator, such as "machine_mode" for modes. */
+ const char *type;
+
/* Treat the given string as the name of a standard mode, etc., and
return its integer value. */
int (*find_builtin) (const char *);
@@ -80,6 +83,9 @@ struct iterator_group {
If the iterator applies to operands, the second argument gives the
operand index, otherwise it is ignored. */
void (*apply_iterator) (rtx, unsigned int, int);
+
+ /* Return the C token for the given standard mode, code, etc. */
+ const char *(*get_c_token) (int);
};
/* Records one use of an iterator. */
@@ -163,6 +169,12 @@ apply_mode_iterator (rtx x, unsigned int, int mode)
PUT_MODE (x, (machine_mode) mode);
}
+static const char *
+get_mode_token (int mode)
+{
+ return concat ("E_", GET_MODE_NAME (mode), "mode", NULL);
+}
+
/* In compact dumps, the code of insns is prefixed with "c", giving "cinsn",
"cnote" etc, and CODE_LABEL is special-cased as "clabel". */
@@ -206,6 +218,15 @@ apply_code_iterator (rtx x, unsigned int, int code)
PUT_CODE (x, (enum rtx_code) code);
}
+static const char *
+get_code_token (int code)
+{
+ char *name = xstrdup (GET_RTX_NAME (code));
+ for (int i = 0; name[i]; ++i)
+ name[i] = TOUPPER (name[i]);
+ return name;
+}
+
/* Implementations of the iterator_group callbacks for ints. */
/* Since GCC does not construct a table of valid constants,
@@ -228,6 +249,14 @@ apply_int_iterator (rtx x, unsigned int index, int value)
XINT (x, index) = value;
}
+static const char *
+get_int_token (int value)
+{
+ char buffer[HOST_BITS_PER_INT + 1];
+ sprintf (buffer, "%d", value);
+ return xstrdup (buffer);
+}
+
#ifdef GENERATOR_FILE
/* This routine adds attribute or does nothing depending on VALUE. When
@@ -317,10 +346,11 @@ find_subst_iter_by_attr (const char *attr)
}
/* Map attribute string P to its current value. Return null if the attribute
- isn't known. */
+ isn't known. If ITERATOR_OUT is nonnull, store the associated iterator
+ there. */
static struct map_value *
-map_attr_string (const char *p)
+map_attr_string (const char *p, mapping **iterator_out = 0)
{
const char *attr;
struct mapping *iterator;
@@ -369,7 +399,11 @@ map_attr_string (const char *p)
iterator value. */
for (v = m->values; v; v = v->next)
if (v->number == iterator->current_value->number)
- return v;
+ {
+ if (iterator_out)
+ *iterator_out = iterator;
+ return v;
+ }
}
}
return NULL;
@@ -545,6 +579,178 @@ add_current_iterators (void **slot, void *data ATTRIBUTE_UNUSED)
return 1;
}
+/* Return a hash value for overloaded_name UNCAST_ONAME. There shouldn't
+ be many instances of two overloaded_names having the same name but
+ different arguments, so hashing on the name should be good enough in
+ practice. */
+
+static hashval_t
+overloaded_name_hash (const void *uncast_oname)
+{
+ const overloaded_name *oname = (const overloaded_name *) uncast_oname;
+ return htab_hash_string (oname->name);
+}
+
+/* Return true if two overloaded_names are similar enough to share
+ the same generated functions. */
+
+static int
+overloaded_name_eq_p (const void *uncast_oname1, const void *uncast_oname2)
+{
+ const overloaded_name *oname1 = (const overloaded_name *) uncast_oname1;
+ const overloaded_name *oname2 = (const overloaded_name *) uncast_oname2;
+ if (strcmp (oname1->name, oname2->name) != 0
+ || oname1->arg_types.length () != oname2->arg_types.length ())
+ return 0;
+
+ for (unsigned int i = 0; i < oname1->arg_types.length (); ++i)
+ if (strcmp (oname1->arg_types[i], oname2->arg_types[i]) != 0)
+ return 0;
+
+ return 1;
+}
+
+/* Return true if X has an instruction name in XSTR (X, 0). */
+
+static bool
+named_rtx_p (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case DEFINE_EXPAND:
+ case DEFINE_INSN:
+ case DEFINE_INSN_AND_SPLIT:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Check whether ORIGINAL is a named pattern whose name starts with '@'.
+ If so, return the associated overloaded_name and add the iterator for
+ each argument to ITERATORS. Return null otherwise. */
+
+overloaded_name *
+md_reader::handle_overloaded_name (rtx original, vec<mapping *> *iterators)
+{
+ /* Check for the leading '@'. */
+ if (!named_rtx_p (original) || XSTR (original, 0)[0] != '@')
+ return NULL;
+
+ /* Remove the '@', so that no other code needs to worry about it. */
+ const char *name = XSTR (original, 0);
+ copy_md_ptr_loc (name + 1, name);
+ name += 1;
+ XSTR (original, 0) = name;
+
+ /* Build a copy of the name without the '<...>' attribute strings.
+ Add the iterator associated with each such attribute string to ITERATORS
+ and add an associated argument to TMP_ONAME. */
+ char *copy = ASTRDUP (name);
+ char *base = copy, *start, *end;
+ overloaded_name tmp_oname;
+ tmp_oname.arg_types.create (current_iterators.length ());
+ bool pending_underscore_p = false;
+ while ((start = strchr (base, '<')) && (end = strchr (start, '>')))
+ {
+ *end = 0;
+ mapping *iterator;
+ if (!map_attr_string (start + 1, &iterator))
+ fatal_with_file_and_line ("unknown iterator `%s'", start + 1);
+ *end = '>';
+
+ /* Remove a trailing underscore, so that we don't end a name
+ with "_" or turn "_<...>_" into "__". */
+ if (start != base && start[-1] == '_')
+ {
+ start -= 1;
+ pending_underscore_p = true;
+ }
+
+ /* Add the text between either the last '>' or the start of
+ the string and this '<'. */
+ obstack_grow (&m_string_obstack, base, start - base);
+ base = end + 1;
+
+ /* If there's a character we need to keep after the '>', check
+ whether we should prefix it with a previously-dropped '_'. */
+ if (base[0] != 0 && base[0] != '<')
+ {
+ if (pending_underscore_p && base[0] != '_')
+ obstack_1grow (&m_string_obstack, '_');
+ pending_underscore_p = false;
+ }
+
+ /* Record an argument for ITERATOR. */
+ iterators->safe_push (iterator);
+ tmp_oname.arg_types.safe_push (iterator->group->type);
+ }
+ if (base == copy)
+ fatal_with_file_and_line ("no iterator attributes in name `%s'", name);
+
+ size_t length = obstack_object_size (&m_string_obstack);
+ if (length == 0)
+ fatal_with_file_and_line ("`%s' only contains iterator attributes", name);
+
+ /* Get the completed name. */
+ obstack_grow (&m_string_obstack, base, strlen (base) + 1);
+ char *new_name = XOBFINISH (&m_string_obstack, char *);
+ tmp_oname.name = new_name;
+
+ if (!m_overloads_htab)
+ m_overloads_htab = htab_create (31, overloaded_name_hash,
+ overloaded_name_eq_p, NULL);
+
+ /* See whether another pattern had the same overload name and list
+ of argument types. Create a new permanent one if not. */
+ void **slot = htab_find_slot (m_overloads_htab, &tmp_oname, INSERT);
+ overloaded_name *oname = (overloaded_name *) *slot;
+ if (!oname)
+ {
+ *slot = oname = new overloaded_name;
+ oname->name = tmp_oname.name;
+ oname->arg_types = tmp_oname.arg_types;
+ oname->next = NULL;
+ oname->first_instance = NULL;
+ oname->next_instance_ptr = &oname->first_instance;
+
+ *m_next_overload_ptr = oname;
+ m_next_overload_ptr = &oname->next;
+ }
+ else
+ {
+ obstack_free (&m_string_obstack, new_name);
+ tmp_oname.arg_types.release ();
+ }
+
+ return oname;
+}
+
+/* Add an instance of ONAME for instruction pattern X. ITERATORS[I]
+ gives the iterator associated with argument I of ONAME. */
+
+static void
+add_overload_instance (overloaded_name *oname, vec<mapping *> iterators, rtx x)
+{
+ /* Create the instance. */
+ overloaded_instance *instance = new overloaded_instance;
+ instance->next = NULL;
+ instance->arg_values.create (oname->arg_types.length ());
+ for (unsigned int i = 0; i < iterators.length (); ++i)
+ {
+ int value = iterators[i]->current_value->number;
+ const char *name = iterators[i]->group->get_c_token (value);
+ instance->arg_values.quick_push (name);
+ }
+ instance->name = XSTR (x, 0);
+ instance->insn = x;
+
+ /* Chain it onto the end of ONAME's list. */
+ *oname->next_instance_ptr = instance;
+ oname->next_instance_ptr = &instance->next;
+}
+
/* Expand all iterators in the current rtx, which is given as ORIGINAL.
Build a list of expanded rtxes in the EXPR_LIST pointed to by QUEUE. */
@@ -562,6 +768,10 @@ apply_iterators (rtx original, vec<rtx> *queue)
{
/* Raise an error if any attributes were used. */
apply_attribute_uses ();
+
+ if (named_rtx_p (original) && XSTR (original, 0)[0] == '@')
+ fatal_with_file_and_line ("'@' used without iterators");
+
queue->safe_push (original);
return;
}
@@ -583,6 +793,11 @@ apply_iterators (rtx original, vec<rtx> *queue)
htab_traverse (substs.iterators, add_current_iterators, NULL);
gcc_assert (!current_iterators.is_empty ());
+ /* Check whether this is a '@' overloaded pattern. */
+ auto_vec<mapping *, 16> iterators;
+ overloaded_name *oname
+ = rtx_reader_ptr->handle_overloaded_name (original, &iterators);
+
for (;;)
{
/* Apply the current iterator values. Accumulate a condition to
@@ -616,6 +831,10 @@ apply_iterators (rtx original, vec<rtx> *queue)
v->number);
}
}
+
+ if (oname)
+ add_overload_instance (oname, iterators, x);
+
/* Add the new rtx to the end of the queue. */
queue->safe_push (x);
@@ -692,28 +911,36 @@ initialize_iterators (void)
modes.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0);
modes.iterators = htab_create (13, leading_string_hash,
leading_string_eq_p, 0);
+ modes.type = "machine_mode";
modes.find_builtin = find_mode;
modes.apply_iterator = apply_mode_iterator;
+ modes.get_c_token = get_mode_token;
codes.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0);
codes.iterators = htab_create (13, leading_string_hash,
leading_string_eq_p, 0);
+ codes.type = "rtx_code";
codes.find_builtin = find_code;
codes.apply_iterator = apply_code_iterator;
+ codes.get_c_token = get_code_token;
ints.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0);
ints.iterators = htab_create (13, leading_string_hash,
leading_string_eq_p, 0);
+ ints.type = "int";
ints.find_builtin = find_int;
ints.apply_iterator = apply_int_iterator;
+ ints.get_c_token = get_int_token;
substs.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0);
substs.iterators = htab_create (13, leading_string_hash,
leading_string_eq_p, 0);
+ substs.type = "int";
substs.find_builtin = find_int; /* We don't use it, anyway. */
#ifdef GENERATOR_FILE
substs.apply_iterator = apply_subst_iterator;
#endif
+ substs.get_c_token = get_int_token;
lower = add_mapping (&modes, modes.attrs, "mode");
upper = add_mapping (&modes, modes.attrs, "MODE");