gencfn-macros.c 8.05 KB
Newer Older
1
/* Generate macros based on the combined_fn enum.
2
   Copyright (C) 2015-2018 Free Software Foundation, Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

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/>.  */

/* 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:

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
   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)  */
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

#include "bconfig.h"
#include "system.h"
#include "coretypes.h"
#include "hash-table.h"
#include "hash-set.h"
#include "errors.h"

typedef hash_set <nofree_string_hash> 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_<NAME><SUFFIX> 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
97 98 99 100
   CFN_<NAME> also exists.  FLOATN_P is a suffix to the operator name, blank
   for normal operators, "_FN" for _Float<N>/_Float<N>X operators only, and
   "_ALL" for both the traditional operators and the _Float<N>/_Float<N>X
   operators.  */
101 102 103

static void
print_case_cfn (const char *name, bool internal_p,
104
		const char *const *suffixes, const char *floatn)
105
{
106
  printf ("#define CASE_CFN_%s%s", name, floatn);
107
  if (internal_p)
108
    printf (" \\\n  case CFN_%s%s", name, floatn);
109 110 111 112 113 114
  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");
}

115 116 117 118 119 120
/* 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_<NAME> also exists.  FLOATN_P is a suffix to the operator name, blank
   for normal operators, "_FN" for _Float<N>/_Float<N>X operators only, and
   "_ALL" for both the traditional operators and the _Float<N>/_Float<N>X
   operators.  */
121 122 123

static void
print_define_operator_list (const char *name, bool internal_p,
124 125
			    const char *const *suffixes,
			    const char *floatn)
126
{
127
  printf ("(define_operator_list %s%s\n", name, floatn);
128 129 130 131 132 133 134 135
  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");
}

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
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 };
158 159
static const char *const fltfn_suffixes[] = { "F16", "F32", "F64", "F128",
					      "F32X", "F64X", "F128X", NULL };
160 161 162
static const char *const fltall_suffixes[] = { "F", "", "L", "F16", "F32",
					       "F64", "F128", "F32X", "F64X",
					       "F128X", NULL };
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
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] != '-'
178
      || !strchr ("co", argv[1][1])
179
      || argv[1][2])
180 181
    fatal ("usage: %s [-c|-o] > file", progname);
  int type = argv[1][1];
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214

  /* 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 (strncmp (name, "BUILT_IN_", 9) == 0)
	{
	  const char *root = name + 9;
	  for (unsigned int j = 0; suffix_lists[j]; ++j)
215 216 217 218 219 220 221 222
	    {
	      const char *const *const suffix = suffix_lists[j];

	      if (is_group (&builtins, root, suffix))
		{
		  bool internal_p = internal_fns.contains (root);

		  if (type == 'c')
223
		    print_case_cfn (root, internal_p, suffix, "");
224
		  else
225
		    print_define_operator_list (root, internal_p, suffix, "");
226 227

		      /* Support the _Float<N> and _Float<N>X math functions if
228 229 230 231 232
			 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<N> and _Float<N>X versions.  */
233 234 235 236
		  if (suffix == flt_suffixes
		      && is_group (&builtins, root, fltfn_suffixes))
		    {
		      if (type == 'c')
237 238 239 240
			{
			  print_case_cfn (root, false, fltfn_suffixes, "_FN");
			  print_case_cfn (root, false, fltall_suffixes, "_ALL");
			}
241
		      else
242 243 244 245 246 247
			{
			  print_define_operator_list (root, false,
						      fltfn_suffixes, "_FN");
			  print_define_operator_list (root, internal_p,
						      fltall_suffixes, "_ALL");
			}
248 249 250
		    }
		}
	    }
251 252 253 254 255 256 257
	}
    }

  if (fflush (stdout) || fclose (stdout) || have_error)
    return FATAL_EXIT_CODE;
  return SUCCESS_EXIT_CODE;
}