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
457 lines
14 KiB
C
457 lines
14 KiB
C
/* Generate code to initialize optabs from machine description.
|
|
Copyright (C) 1993-2018 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 "gensupport.h"
|
|
|
|
|
|
#define DEF_RTL_EXPR(V, N, X, C) #V,
|
|
|
|
static const char * const rtx_upname[] = {
|
|
#include "rtl.def"
|
|
};
|
|
|
|
#undef DEF_RTL_EXPR
|
|
|
|
/* Vector in which to collect insns that match. */
|
|
static vec<optab_pattern> patterns;
|
|
|
|
static void
|
|
gen_insn (md_rtx_info *info)
|
|
{
|
|
optab_pattern p;
|
|
if (find_optab (&p, XSTR (info->def, 0)))
|
|
patterns.safe_push (p);
|
|
}
|
|
|
|
static int
|
|
pattern_cmp (const void *va, const void *vb)
|
|
{
|
|
const optab_pattern *a = (const optab_pattern *)va;
|
|
const optab_pattern *b = (const optab_pattern *)vb;
|
|
return a->sort_num - b->sort_num;
|
|
}
|
|
|
|
static int
|
|
optab_kind_cmp (const void *va, const void *vb)
|
|
{
|
|
const optab_def *a = (const optab_def *)va;
|
|
const optab_def *b = (const optab_def *)vb;
|
|
int diff = a->kind - b->kind;
|
|
if (diff == 0)
|
|
diff = a->op - b->op;
|
|
return diff;
|
|
}
|
|
|
|
static int
|
|
optab_rcode_cmp (const void *va, const void *vb)
|
|
{
|
|
const optab_def *a = (const optab_def *)va;
|
|
const optab_def *b = (const optab_def *)vb;
|
|
return a->rcode - b->rcode;
|
|
}
|
|
|
|
static const char *header_file_name = "init-opinit.h";
|
|
static const char *source_file_name = "init-opinit.c";
|
|
|
|
static bool
|
|
handle_arg (const char *arg)
|
|
{
|
|
switch (arg[1])
|
|
{
|
|
case 'h':
|
|
header_file_name = &arg[2];
|
|
return true;
|
|
case 'c':
|
|
source_file_name = &arg[2];
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static FILE *
|
|
open_outfile (const char *file_name)
|
|
{
|
|
FILE *f = fopen (file_name, "w");
|
|
if (!f)
|
|
fatal ("cannot open file %s: %s", file_name, xstrerror (errno));
|
|
fprintf (f,
|
|
"/* Generated automatically by the program `genopinit'\n"
|
|
" from the machine description file `md'. */\n\n");
|
|
return f;
|
|
}
|
|
|
|
/* Declare the maybe_code_for_* function for ONAME, and provide
|
|
an inline definition of the assserting code_for_* wrapper. */
|
|
|
|
static void
|
|
handle_overloaded_code_for (FILE *file, overloaded_name *oname)
|
|
{
|
|
fprintf (file, "\nextern insn_code maybe_code_for_%s (", oname->name);
|
|
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
|
|
fprintf (file, "%s%s", i == 0 ? "" : ", ", oname->arg_types[i]);
|
|
fprintf (file, ");\n");
|
|
|
|
fprintf (file, "inline insn_code\ncode_for_%s (", oname->name);
|
|
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
|
|
fprintf (file, "%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
|
|
fprintf (file, ")\n{\n insn_code code = maybe_code_for_%s (", oname->name);
|
|
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
|
|
fprintf (file, "%sarg%d", i == 0 ? "" : ", ", i);
|
|
fprintf (file,
|
|
");\n"
|
|
" gcc_assert (code != CODE_FOR_nothing);\n"
|
|
" return code;\n"
|
|
"}\n");
|
|
}
|
|
|
|
/* Declare the maybe_gen_* function for ONAME, and provide
|
|
an inline definition of the assserting gen_* wrapper. */
|
|
|
|
static void
|
|
handle_overloaded_gen (FILE *file, overloaded_name *oname)
|
|
{
|
|
pattern_stats stats;
|
|
get_pattern_stats (&stats, XVEC (oname->first_instance->insn, 1));
|
|
|
|
fprintf (file, "\nextern rtx maybe_gen_%s (", oname->name);
|
|
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
|
|
fprintf (file, "%s%s", i == 0 ? "" : ", ", oname->arg_types[i]);
|
|
for (int i = 0; i < stats.num_generator_args; ++i)
|
|
fprintf (file, ", rtx");
|
|
fprintf (file, ");\n");
|
|
|
|
fprintf (file, "inline rtx\ngen_%s (", oname->name);
|
|
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
|
|
fprintf (file, "%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
|
|
for (int i = 0; i < stats.num_generator_args; ++i)
|
|
fprintf (file, ", rtx x%d", i);
|
|
fprintf (file, ")\n{\n rtx res = maybe_gen_%s (", oname->name);
|
|
for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
|
|
fprintf (file, "%sarg%d", i == 0 ? "" : ", ", i);
|
|
for (int i = 0; i < stats.num_generator_args; ++i)
|
|
fprintf (file, ", x%d", i);
|
|
fprintf (file,
|
|
");\n"
|
|
" gcc_assert (res);\n"
|
|
" return res;\n"
|
|
"}\n");
|
|
}
|
|
|
|
int
|
|
main (int argc, const char **argv)
|
|
{
|
|
FILE *h_file, *s_file;
|
|
unsigned int i, j, n, last_kind[5];
|
|
optab_pattern *p;
|
|
|
|
progname = "genopinit";
|
|
|
|
if (NUM_OPTABS > 0xffff || MAX_MACHINE_MODE >= 0xff)
|
|
fatal ("genopinit range assumptions invalid");
|
|
|
|
if (!init_rtx_reader_args_cb (argc, argv, handle_arg))
|
|
return (FATAL_EXIT_CODE);
|
|
|
|
h_file = open_outfile (header_file_name);
|
|
s_file = open_outfile (source_file_name);
|
|
|
|
/* Read the machine description. */
|
|
md_rtx_info info;
|
|
while (read_md_rtx (&info))
|
|
switch (GET_CODE (info.def))
|
|
{
|
|
case DEFINE_INSN:
|
|
case DEFINE_EXPAND:
|
|
gen_insn (&info);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Sort the collected patterns. */
|
|
patterns.qsort (pattern_cmp);
|
|
|
|
/* Now that we've handled the "extra" patterns, eliminate them from
|
|
the optabs array. That way they don't get in the way below. */
|
|
n = num_optabs;
|
|
for (i = 0; i < n; )
|
|
if (optabs[i].base == NULL)
|
|
optabs[i] = optabs[--n];
|
|
else
|
|
++i;
|
|
|
|
/* Sort the (real) optabs. Better than forcing the optabs.def file to
|
|
remain sorted by kind. We also scrogged any real ordering with the
|
|
purging of the X patterns above. */
|
|
qsort (optabs, n, sizeof (optab_def), optab_kind_cmp);
|
|
|
|
fprintf (h_file, "#ifndef GCC_INSN_OPINIT_H\n");
|
|
fprintf (h_file, "#define GCC_INSN_OPINIT_H 1\n");
|
|
|
|
/* Emit the optab enumeration for the header file. */
|
|
fprintf (h_file, "enum optab_tag {\n");
|
|
for (i = j = 0; i < n; ++i)
|
|
{
|
|
optabs[i].op = i;
|
|
fprintf (h_file, " %s,\n", optabs[i].name);
|
|
if (optabs[i].kind != j)
|
|
last_kind[j++] = i - 1;
|
|
}
|
|
fprintf (h_file, " FIRST_CONV_OPTAB = %s,\n", optabs[last_kind[0]+1].name);
|
|
fprintf (h_file, " LAST_CONVLIB_OPTAB = %s,\n", optabs[last_kind[1]].name);
|
|
fprintf (h_file, " LAST_CONV_OPTAB = %s,\n", optabs[last_kind[2]].name);
|
|
fprintf (h_file, " FIRST_NORM_OPTAB = %s,\n", optabs[last_kind[2]+1].name);
|
|
fprintf (h_file, " LAST_NORMLIB_OPTAB = %s,\n", optabs[last_kind[3]].name);
|
|
fprintf (h_file, " LAST_NORM_OPTAB = %s\n", optabs[i-1].name);
|
|
fprintf (h_file, "};\n\n");
|
|
|
|
fprintf (h_file, "#define NUM_OPTABS %u\n", n);
|
|
fprintf (h_file, "#define NUM_CONVLIB_OPTABS %u\n",
|
|
last_kind[1] - last_kind[0]);
|
|
fprintf (h_file, "#define NUM_NORMLIB_OPTABS %u\n",
|
|
last_kind[3] - last_kind[2]);
|
|
fprintf (h_file, "#define NUM_OPTAB_PATTERNS %u\n",
|
|
(unsigned) patterns.length ());
|
|
|
|
fprintf (h_file,
|
|
"typedef enum optab_tag optab;\n"
|
|
"typedef enum optab_tag convert_optab;\n"
|
|
"typedef enum optab_tag direct_optab;\n"
|
|
"\n"
|
|
"struct optab_libcall_d\n"
|
|
"{\n"
|
|
" char libcall_suffix;\n"
|
|
" const char *libcall_basename;\n"
|
|
" void (*libcall_gen) (optab, const char *name,\n"
|
|
" char suffix, machine_mode);\n"
|
|
"};\n"
|
|
"\n"
|
|
"struct convert_optab_libcall_d\n"
|
|
"{\n"
|
|
" const char *libcall_basename;\n"
|
|
" void (*libcall_gen) (convert_optab, const char *name,\n"
|
|
" machine_mode, machine_mode);\n"
|
|
"};\n"
|
|
"\n"
|
|
"/* Given an enum insn_code, access the function to construct\n"
|
|
" the body of that kind of insn. */\n"
|
|
"#define GEN_FCN(CODE) (insn_data[CODE].genfun)\n"
|
|
"\n"
|
|
"#ifdef NUM_RTX_CODE\n"
|
|
"/* Contains the optab used for each rtx code, and vice-versa. */\n"
|
|
"extern const optab code_to_optab_[NUM_RTX_CODE];\n"
|
|
"extern const enum rtx_code optab_to_code_[NUM_OPTABS];\n"
|
|
"\n"
|
|
"static inline optab\n"
|
|
"code_to_optab (enum rtx_code code)\n"
|
|
"{\n"
|
|
" return code_to_optab_[code];\n"
|
|
"}\n"
|
|
"\n"
|
|
"static inline enum rtx_code\n"
|
|
"optab_to_code (optab op)\n"
|
|
"{\n"
|
|
" return optab_to_code_[op];\n"
|
|
"}\n");
|
|
|
|
for (overloaded_name *oname = rtx_reader_ptr->get_overloads ();
|
|
oname; oname = oname->next)
|
|
{
|
|
handle_overloaded_code_for (h_file, oname);
|
|
handle_overloaded_gen (h_file, oname);
|
|
}
|
|
|
|
fprintf (h_file,
|
|
"#endif\n"
|
|
"\n"
|
|
"extern const struct convert_optab_libcall_d convlib_def[NUM_CONVLIB_OPTABS];\n"
|
|
"extern const struct optab_libcall_d normlib_def[NUM_NORMLIB_OPTABS];\n"
|
|
"\n"
|
|
"/* Returns the active icode for the given (encoded) optab. */\n"
|
|
"extern enum insn_code raw_optab_handler (unsigned);\n"
|
|
"extern bool swap_optab_enable (optab, machine_mode, bool);\n"
|
|
"\n"
|
|
"/* Target-dependent globals. */\n"
|
|
"struct target_optabs {\n"
|
|
" /* Patterns that are used by optabs that are enabled for this target. */\n"
|
|
" bool pat_enable[NUM_OPTAB_PATTERNS];\n"
|
|
"\n"
|
|
" /* Cache if the target supports vec_gather_load for at least one vector\n"
|
|
" mode. */\n"
|
|
" bool supports_vec_gather_load;\n"
|
|
" bool supports_vec_gather_load_cached;\n"
|
|
" bool supports_vec_scatter_store;\n"
|
|
" bool supports_vec_scatter_store_cached;\n"
|
|
"};\n"
|
|
"extern void init_all_optabs (struct target_optabs *);\n"
|
|
"\n"
|
|
"extern struct target_optabs default_target_optabs;\n"
|
|
"extern struct target_optabs *this_fn_optabs;\n"
|
|
"#if SWITCHABLE_TARGET\n"
|
|
"extern struct target_optabs *this_target_optabs;\n"
|
|
"#else\n"
|
|
"#define this_target_optabs (&default_target_optabs)\n"
|
|
"#endif\n");
|
|
|
|
fprintf (s_file,
|
|
"#define IN_TARGET_CODE 1\n"
|
|
"#include \"config.h\"\n"
|
|
"#include \"system.h\"\n"
|
|
"#include \"coretypes.h\"\n"
|
|
"#include \"backend.h\"\n"
|
|
"#include \"predict.h\"\n"
|
|
"#include \"tree.h\"\n"
|
|
"#include \"rtl.h\"\n"
|
|
"#include \"alias.h\"\n"
|
|
"#include \"varasm.h\"\n"
|
|
"#include \"stor-layout.h\"\n"
|
|
"#include \"calls.h\"\n"
|
|
"#include \"memmodel.h\"\n"
|
|
"#include \"tm_p.h\"\n"
|
|
"#include \"flags.h\"\n"
|
|
"#include \"insn-config.h\"\n"
|
|
"#include \"expmed.h\"\n"
|
|
"#include \"dojump.h\"\n"
|
|
"#include \"explow.h\"\n"
|
|
"#include \"emit-rtl.h\"\n"
|
|
"#include \"stmt.h\"\n"
|
|
"#include \"expr.h\"\n"
|
|
"#include \"insn-codes.h\"\n"
|
|
"#include \"optabs.h\"\n"
|
|
"\n"
|
|
"struct optab_pat {\n"
|
|
" unsigned scode;\n"
|
|
" enum insn_code icode;\n"
|
|
"};\n\n");
|
|
|
|
fprintf (s_file,
|
|
"static const struct optab_pat pats[NUM_OPTAB_PATTERNS] = {\n");
|
|
for (i = 0; patterns.iterate (i, &p); ++i)
|
|
fprintf (s_file, " { %#08x, CODE_FOR_%s },\n", p->sort_num, p->name);
|
|
fprintf (s_file, "};\n\n");
|
|
|
|
fprintf (s_file, "void\ninit_all_optabs (struct target_optabs *optabs)\n{\n");
|
|
fprintf (s_file, " bool *ena = optabs->pat_enable;\n");
|
|
for (i = 0; patterns.iterate (i, &p); ++i)
|
|
fprintf (s_file, " ena[%u] = HAVE_%s;\n", i, p->name);
|
|
fprintf (s_file, "}\n\n");
|
|
|
|
/* Perform a binary search on a pre-encoded optab+mode*2. */
|
|
/* ??? Perhaps even better to generate a minimal perfect hash.
|
|
Using gperf directly is awkward since it's so geared to working
|
|
with strings. Plus we have no visibility into the ordering of
|
|
the hash entries, which complicates the pat_enable array. */
|
|
fprintf (s_file,
|
|
"static int\n"
|
|
"lookup_handler (unsigned scode)\n"
|
|
"{\n"
|
|
" int l = 0, h = ARRAY_SIZE (pats), m;\n"
|
|
" while (h > l)\n"
|
|
" {\n"
|
|
" m = (h + l) / 2;\n"
|
|
" if (scode == pats[m].scode)\n"
|
|
" return m;\n"
|
|
" else if (scode < pats[m].scode)\n"
|
|
" h = m;\n"
|
|
" else\n"
|
|
" l = m + 1;\n"
|
|
" }\n"
|
|
" return -1;\n"
|
|
"}\n\n");
|
|
|
|
fprintf (s_file,
|
|
"enum insn_code\n"
|
|
"raw_optab_handler (unsigned scode)\n"
|
|
"{\n"
|
|
" int i = lookup_handler (scode);\n"
|
|
" return (i >= 0 && this_fn_optabs->pat_enable[i]\n"
|
|
" ? pats[i].icode : CODE_FOR_nothing);\n"
|
|
"}\n\n");
|
|
|
|
fprintf (s_file,
|
|
"bool\n"
|
|
"swap_optab_enable (optab op, machine_mode m, bool set)\n"
|
|
"{\n"
|
|
" unsigned scode = (op << 16) | m;\n"
|
|
" int i = lookup_handler (scode);\n"
|
|
" if (i >= 0)\n"
|
|
" {\n"
|
|
" bool ret = this_fn_optabs->pat_enable[i];\n"
|
|
" this_fn_optabs->pat_enable[i] = set;\n"
|
|
" return ret;\n"
|
|
" }\n"
|
|
" else\n"
|
|
" {\n"
|
|
" gcc_assert (!set);\n"
|
|
" return false;\n"
|
|
" }\n"
|
|
"}\n\n");
|
|
|
|
/* C++ (even G++) does not support (non-trivial) designated initializers.
|
|
To work around that, generate these arrays programatically rather than
|
|
by our traditional multiple inclusion of def files. */
|
|
|
|
fprintf (s_file,
|
|
"const struct convert_optab_libcall_d "
|
|
"convlib_def[NUM_CONVLIB_OPTABS] = {\n");
|
|
for (i = last_kind[0] + 1; i <= last_kind[1]; ++i)
|
|
fprintf (s_file, " { %s, %s },\n", optabs[i].base, optabs[i].libcall);
|
|
fprintf (s_file, "};\n\n");
|
|
|
|
fprintf (s_file,
|
|
"const struct optab_libcall_d "
|
|
"normlib_def[NUM_NORMLIB_OPTABS] = {\n");
|
|
for (i = last_kind[2] + 1; i <= last_kind[3]; ++i)
|
|
fprintf (s_file, " { %s, %s, %s },\n",
|
|
optabs[i].suffix, optabs[i].base, optabs[i].libcall);
|
|
fprintf (s_file, "};\n\n");
|
|
|
|
fprintf (s_file, "enum rtx_code const optab_to_code_[NUM_OPTABS] = {\n");
|
|
for (i = 0; i < n; ++i)
|
|
fprintf (s_file, " %s,\n", rtx_upname[optabs[i].fcode]);
|
|
fprintf (s_file, "};\n\n");
|
|
|
|
qsort (optabs, n, sizeof (optab_def), optab_rcode_cmp);
|
|
|
|
fprintf (s_file, "const optab code_to_optab_[NUM_RTX_CODE] = {\n");
|
|
for (j = 0; optabs[j].rcode == UNKNOWN; ++j)
|
|
continue;
|
|
for (i = 0; i < NON_GENERATOR_NUM_RTX_CODE; ++i)
|
|
{
|
|
if (j < n && optabs[j].rcode == i)
|
|
fprintf (s_file, " %s,\n", optabs[j++].name);
|
|
else
|
|
fprintf (s_file, " unknown_optab,\n");
|
|
}
|
|
fprintf (s_file, "};\n\n");
|
|
|
|
fprintf (h_file, "#endif\n");
|
|
return (fclose (h_file) == 0 && fclose (s_file) == 0
|
|
? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE);
|
|
}
|