diff options
author | Richard Sandiford <richard.sandiford@arm.com> | 2018-08-02 10:59:35 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2018-08-02 10:59:35 +0000 |
commit | 0016d8d91cb2880e69be74efb44367b282577977 (patch) | |
tree | c65a69b7b2e33e1f21911fa540f0ce7579294e37 /gcc/read-rtl.c | |
parent | a451882123524de1b9b175af97a1cdd32e5f25c1 (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.c | 233 |
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"); |