/* Generate macros based on the combined_fn enum.
Copyright (C) 2015-2024 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
. */
/* Automatically generate code fragments related to combined_fn.
The program looks for math built-in functions that have float, double
and long double variants, such as {sqrtf, sqrt, sqrtl}, and that may
or may not have an associated internal function as well. It also looks
for integer built-in functions that have int, long, long long and
intmax_t variants, such as {clz, clzl, clzll, clzimax}, and that
again may or may not have an associated internal function as well.
When run with -c, the generator prints a list of macros such as:
CASE_CFN_SQRT
for each group of functions described above, with 'case CFN_*'
statements for each built-in and internal function in the group.
For example, there are both built-in and internal implementations
of SQRT, so "CASE_CFN_SQRT:" is equivalent to:
case CFN_BUILT_IN_SQRTF:
case CFN_BUILT_IN_SQRT:
case CFN_BUILT_IN_SQRTL:
case CFN_SQRT:
The macros for groups with no internal function drop the last line.
When run with -o, the generator prints a similar list of
define_operator_list directives, for use by match.pd. Each operator
list starts with the built-in functions, in order of ascending type width.
This is followed by an entry for the internal function, or "null" if there
is no internal function for the group. For example:
(define_operator_list SQRT
BUILT_IN_SQRTF
BUILT_IN_SQRT
BUILT_IN_SQRTL
IFN_SQRT)
and:
(define_operator_list CABS
BUILT_IN_CABSF
BUILT_IN_CABS
BUILT_IN_CABSL
null) */
#include "bconfig.h"
#include "system.h"
#include "coretypes.h"
#include "hash-table.h"
#include "hash-set.h"
#include "errors.h"
typedef hash_set string_set;
/* Add all names in null-terminated list NAMES to SET. */
static void
add_to_set (string_set *set, const char *const *names)
{
for (unsigned int i = 0; names[i]; ++i)
set->add (names[i]);
}
/* Return true if *BUILTINS contains BUILT_IN_ for all
suffixes in null-terminated list SUFFIXES. */
static bool
is_group (string_set *builtins, const char *name, const char *const *suffixes)
{
for (unsigned int i = 0; suffixes[i]; ++i)
if (!builtins->contains (ACONCAT (("BUILT_IN_", name, suffixes[i], NULL))))
return false;
return true;
}
/* Print a macro for all combined functions related to NAME, with the
null-terminated list of suffixes in SUFFIXES. INTERNAL_P says whether
CFN_ also exists. FLOATN_P is a suffix to the operator name, blank
for normal operators, "_FN" for _Float/_FloatX operators only, and
"_ALL" for both the traditional operators and the _Float/_FloatX
operators. */
static void
print_case_cfn (const char *name, bool internal_p,
const char *const *suffixes, const char *floatn)
{
printf ("#define CASE_CFN_%s%s", name, floatn);
if (internal_p)
printf (" \\\n case CFN_%s%s", name, floatn);
for (unsigned int i = 0; suffixes[i]; ++i)
printf ("%s \\\n case CFN_BUILT_IN_%s%s",
internal_p || i > 0 ? ":" : "", name, suffixes[i]);
printf ("\n");
}
/* Print an operator list for all combined functions related to NAME, with the
null-terminated list of suffixes in SUFFIXES. INTERNAL_P says whether
CFN_ also exists. FLOATN_P is a suffix to the operator name, blank
for normal operators, "_FN" for _Float/_FloatX operators only, and
"_ALL" for both the traditional operators and the _Float/_FloatX
operators. */
static void
print_define_operator_list (const char *name, bool internal_p,
const char *const *suffixes,
const char *floatn)
{
printf ("(define_operator_list %s%s\n", name, floatn);
for (unsigned int i = 0; suffixes[i]; ++i)
printf (" BUILT_IN_%s%s\n", name, suffixes[i]);
if (internal_p)
printf (" IFN_%s)\n", name);
else
printf (" null)\n");
}
const char *const builtin_names[] = {
#define DEF_BUILTIN(ENUM, N, C, T, LT, B, F, NA, AT, IM, COND) \
#ENUM,
#include "builtins.def"
NULL
};
const char *const internal_fn_flt_names[] = {
#define DEF_INTERNAL_FLT_FN(NAME, FLAGS, OPTAB, TYPE) \
#NAME,
#include "internal-fn.def"
NULL
};
const char *const internal_fn_int_names[] = {
#define DEF_INTERNAL_INT_FN(NAME, FLAGS, OPTAB, TYPE) \
#NAME,
#include "internal-fn.def"
NULL
};
static const char *const flt_suffixes[] = { "F", "", "L", NULL };
static const char *const fltfn_suffixes[] = { "F16", "F32", "F64", "F128",
"F32X", "F64X", "F128X", NULL };
static const char *const fltall_suffixes[] = { "F", "", "L", "F16", "F32",
"F64", "F128", "F32X", "F64X",
"F128X", NULL };
static const char *const int_suffixes[] = { "", "L", "LL", "IMAX", NULL };
static const char *const *const suffix_lists[] = {
flt_suffixes,
int_suffixes,
NULL
};
int
main (int argc, char **argv)
{
/* Check arguments. */
progname = argv[0];
if (argc != 2
|| argv[1][0] != '-'
|| !strchr ("co", argv[1][1])
|| argv[1][2])
fatal ("usage: %s [-c|-o] > file", progname);
int type = argv[1][1];
/* Collect the set of built-in and internal functions. */
string_set builtins;
string_set internal_fns;
add_to_set (&builtins, builtin_names);
add_to_set (&internal_fns, internal_fn_flt_names);
add_to_set (&internal_fns, internal_fn_int_names);
/* Check the functions. */
for (unsigned int i = 0; internal_fn_flt_names[i]; ++i)
{
const char *name = internal_fn_flt_names[i];
if (!is_group (&builtins, name, flt_suffixes))
error ("DEF_INTERNAL_FLT_FN (%s) has no associated built-in"
" functions", name);
}
for (unsigned int i = 0; internal_fn_int_names[i]; ++i)
{
const char *name = internal_fn_int_names[i];
if (!is_group (&builtins, name, int_suffixes))
error ("DEF_INTERNAL_INT_FN (%s) has no associated built-in"
" functions", name);
}
/* Go through the built-in functions in declaration order, outputting
definitions as appropriate. */
for (unsigned int i = 0; builtin_names[i]; ++i)
{
const char *name = builtin_names[i];
if (startswith (name, "BUILT_IN_"))
{
const char *root = name + 9;
for (unsigned int j = 0; suffix_lists[j]; ++j)
{
const char *const *const suffix = suffix_lists[j];
if (is_group (&builtins, root, suffix))
{
bool internal_p = internal_fns.contains (root);
if (type == 'c')
print_case_cfn (root, internal_p, suffix, "");
else
print_define_operator_list (root, internal_p, suffix, "");
/* Support the _Float and _FloatX math functions if
they exist. We put these out as a separate CFN or
operator macro, so code can add support or not as
needed. We also put out a combined CFN or operator
macro that includes both the traditional names and the
_Float and _FloatX versions. */
if (suffix == flt_suffixes
&& is_group (&builtins, root, fltfn_suffixes))
{
if (type == 'c')
{
print_case_cfn (root, false, fltfn_suffixes, "_FN");
print_case_cfn (root, false, fltall_suffixes, "_ALL");
}
else
{
print_define_operator_list (root, false,
fltfn_suffixes, "_FN");
print_define_operator_list (root, internal_p,
fltall_suffixes, "_ALL");
}
}
}
}
}
}
if (fflush (stdout) || fclose (stdout) || have_error)
return FATAL_EXIT_CODE;
return SUCCESS_EXIT_CODE;
}