summaryrefslogtreecommitdiff
path: root/gcc/gencfn-macros.c
blob: 269429fabfc8ddefc4390896ebde2ceb7e20be5d (plain)
1
2
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
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
215
216
217
218
/* Generate macros based on the combined_fn enum.
   Copyright (C) 2015-2017 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/>.  */

/* 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 <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
   CFN_<NAME> also exists.  */

static void
print_case_cfn (const char *name, bool internal_p,
		const char *const *suffixes)
{
  printf ("#define CASE_CFN_%s", name);
  if (internal_p)
    printf (" \\\n  case CFN_%s", name);
  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_<NAME> also exists.  */

static void
print_define_operator_list (const char *name, bool internal_p,
			    const char *const *suffixes)
{
  printf ("(define_operator_list %s\n", name);
  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 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 (strncmp (name, "BUILT_IN_", 9) == 0)
	{
	  const char *root = name + 9;
	  for (unsigned int j = 0; suffix_lists[j]; ++j)
	    if (is_group (&builtins, root, suffix_lists[j]))
	      {
		bool internal_p = internal_fns.contains (root);
		if (type == 'c')
		  print_case_cfn (root, internal_p, suffix_lists[j]);
		else
		  print_define_operator_list (root, internal_p,
					      suffix_lists[j]);
	      }
	}
    }

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