1/* Generate macros based on the combined_fn enum.
2 Copyright (C) 2015-2023 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
19
20/* Automatically generate code fragments related to combined_fn.
21
22 The program looks for math built-in functions that have float, double
23 and long double variants, such as {sqrtf, sqrt, sqrtl}, and that may
24 or may not have an associated internal function as well. It also looks
25 for integer built-in functions that have int, long, long long and
26 intmax_t variants, such as {clz, clzl, clzll, clzimax}, and that
27 again may or may not have an associated internal function as well.
28
29 When run with -c, the generator prints a list of macros such as:
30
31 CASE_CFN_SQRT
32
33 for each group of functions described above, with 'case CFN_*'
34 statements for each built-in and internal function in the group.
35 For example, there are both built-in and internal implementations
36 of SQRT, so "CASE_CFN_SQRT:" is equivalent to:
37
38 case CFN_BUILT_IN_SQRTF:
39 case CFN_BUILT_IN_SQRT:
40 case CFN_BUILT_IN_SQRTL:
41 case CFN_SQRT:
42
43 The macros for groups with no internal function drop the last line.
44
45 When run with -o, the generator prints a similar list of
46 define_operator_list directives, for use by match.pd. Each operator
47 list starts with the built-in functions, in order of ascending type width.
48 This is followed by an entry for the internal function, or "null" if there
49 is no internal function for the group. For example:
50
51 (define_operator_list SQRT
52 BUILT_IN_SQRTF
53 BUILT_IN_SQRT
54 BUILT_IN_SQRTL
55 IFN_SQRT)
56
57 and:
58
59 (define_operator_list CABS
60 BUILT_IN_CABSF
61 BUILT_IN_CABS
62 BUILT_IN_CABSL
63 null) */
64
65#include "bconfig.h"
66#include "system.h"
67#include "coretypes.h"
68#include "hash-table.h"
69#include "hash-set.h"
70#include "errors.h"
71
72typedef hash_set <nofree_string_hash> string_set;
73
74/* Add all names in null-terminated list NAMES to SET. */
75
76static void
77add_to_set (string_set *set, const char *const *names)
78{
79 for (unsigned int i = 0; names[i]; ++i)
80 set->add (k: names[i]);
81}
82
83/* Return true if *BUILTINS contains BUILT_IN_<NAME><SUFFIX> for all
84 suffixes in null-terminated list SUFFIXES. */
85
86static bool
87is_group (string_set *builtins, const char *name, const char *const *suffixes)
88{
89 for (unsigned int i = 0; suffixes[i]; ++i)
90 if (!builtins->contains (ACONCAT (("BUILT_IN_", name, suffixes[i], NULL))))
91 return false;
92 return true;
93}
94
95/* Print a macro for all combined functions related to NAME, with the
96 null-terminated list of suffixes in SUFFIXES. INTERNAL_P says whether
97 CFN_<NAME> also exists. FLOATN_P is a suffix to the operator name, blank
98 for normal operators, "_FN" for _Float<N>/_Float<N>X operators only, and
99 "_ALL" for both the traditional operators and the _Float<N>/_Float<N>X
100 operators. */
101
102static void
103print_case_cfn (const char *name, bool internal_p,
104 const char *const *suffixes, const char *floatn)
105{
106 printf (format: "#define CASE_CFN_%s%s", name, floatn);
107 if (internal_p)
108 printf (format: " \\\n case CFN_%s%s", name, floatn);
109 for (unsigned int i = 0; suffixes[i]; ++i)
110 printf (format: "%s \\\n case CFN_BUILT_IN_%s%s",
111 internal_p || i > 0 ? ":" : "", name, suffixes[i]);
112 printf (format: "\n");
113}
114
115/* Print an operator list for all combined functions related to NAME, with the
116 null-terminated list of suffixes in SUFFIXES. INTERNAL_P says whether
117 CFN_<NAME> also exists. FLOATN_P is a suffix to the operator name, blank
118 for normal operators, "_FN" for _Float<N>/_Float<N>X operators only, and
119 "_ALL" for both the traditional operators and the _Float<N>/_Float<N>X
120 operators. */
121
122static void
123print_define_operator_list (const char *name, bool internal_p,
124 const char *const *suffixes,
125 const char *floatn)
126{
127 printf (format: "(define_operator_list %s%s\n", name, floatn);
128 for (unsigned int i = 0; suffixes[i]; ++i)
129 printf (format: " BUILT_IN_%s%s\n", name, suffixes[i]);
130 if (internal_p)
131 printf (format: " IFN_%s)\n", name);
132 else
133 printf (format: " null)\n");
134}
135
136const char *const builtin_names[] = {
137#define DEF_BUILTIN(ENUM, N, C, T, LT, B, F, NA, AT, IM, COND) \
138 #ENUM,
139#include "builtins.def"
140 NULL
141};
142
143const char *const internal_fn_flt_names[] = {
144#define DEF_INTERNAL_FLT_FN(NAME, FLAGS, OPTAB, TYPE) \
145 #NAME,
146#include "internal-fn.def"
147 NULL
148};
149
150const char *const internal_fn_int_names[] = {
151#define DEF_INTERNAL_INT_FN(NAME, FLAGS, OPTAB, TYPE) \
152 #NAME,
153#include "internal-fn.def"
154 NULL
155};
156
157static const char *const flt_suffixes[] = { "F", "", "L", NULL };
158static const char *const fltfn_suffixes[] = { "F16", "F32", "F64", "F128",
159 "F32X", "F64X", "F128X", NULL };
160static const char *const fltall_suffixes[] = { "F", "", "L", "F16", "F32",
161 "F64", "F128", "F32X", "F64X",
162 "F128X", NULL };
163static const char *const int_suffixes[] = { "", "L", "LL", "IMAX", NULL };
164
165static const char *const *const suffix_lists[] = {
166 flt_suffixes,
167 int_suffixes,
168 NULL
169};
170
171int
172main (int argc, char **argv)
173{
174 /* Check arguments. */
175 progname = argv[0];
176 if (argc != 2
177 || argv[1][0] != '-'
178 || !strchr (s: "co", c: argv[1][1])
179 || argv[1][2])
180 fatal ("usage: %s [-c|-o] > file", progname);
181 int type = argv[1][1];
182
183 /* Collect the set of built-in and internal functions. */
184 string_set builtins;
185 string_set internal_fns;
186 add_to_set (set: &builtins, names: builtin_names);
187 add_to_set (set: &internal_fns, names: internal_fn_flt_names);
188 add_to_set (set: &internal_fns, names: internal_fn_int_names);
189
190 /* Check the functions. */
191 for (unsigned int i = 0; internal_fn_flt_names[i]; ++i)
192 {
193 const char *name = internal_fn_flt_names[i];
194 if (!is_group (builtins: &builtins, name, suffixes: flt_suffixes))
195 error ("DEF_INTERNAL_FLT_FN (%s) has no associated built-in"
196 " functions", name);
197 }
198 for (unsigned int i = 0; internal_fn_int_names[i]; ++i)
199 {
200 const char *name = internal_fn_int_names[i];
201 if (!is_group (builtins: &builtins, name, suffixes: int_suffixes))
202 error ("DEF_INTERNAL_INT_FN (%s) has no associated built-in"
203 " functions", name);
204 }
205
206 /* Go through the built-in functions in declaration order, outputting
207 definitions as appropriate. */
208 for (unsigned int i = 0; builtin_names[i]; ++i)
209 {
210 const char *name = builtin_names[i];
211 if (startswith (str: name, prefix: "BUILT_IN_"))
212 {
213 const char *root = name + 9;
214 for (unsigned int j = 0; suffix_lists[j]; ++j)
215 {
216 const char *const *const suffix = suffix_lists[j];
217
218 if (is_group (builtins: &builtins, name: root, suffixes: suffix))
219 {
220 bool internal_p = internal_fns.contains (k: root);
221
222 if (type == 'c')
223 print_case_cfn (name: root, internal_p, suffixes: suffix, floatn: "");
224 else
225 print_define_operator_list (name: root, internal_p, suffixes: suffix, floatn: "");
226
227 /* Support the _Float<N> and _Float<N>X math functions if
228 they exist. We put these out as a separate CFN or
229 operator macro, so code can add support or not as
230 needed. We also put out a combined CFN or operator
231 macro that includes both the traditional names and the
232 _Float<N> and _Float<N>X versions. */
233 if (suffix == flt_suffixes
234 && is_group (builtins: &builtins, name: root, suffixes: fltfn_suffixes))
235 {
236 if (type == 'c')
237 {
238 print_case_cfn (name: root, internal_p: false, suffixes: fltfn_suffixes, floatn: "_FN");
239 print_case_cfn (name: root, internal_p: false, suffixes: fltall_suffixes, floatn: "_ALL");
240 }
241 else
242 {
243 print_define_operator_list (name: root, internal_p: false,
244 suffixes: fltfn_suffixes, floatn: "_FN");
245 print_define_operator_list (name: root, internal_p,
246 suffixes: fltall_suffixes, floatn: "_ALL");
247 }
248 }
249 }
250 }
251 }
252 }
253
254 if (fflush (stdout) || fclose (stdout) || have_error)
255 return FATAL_EXIT_CODE;
256 return SUCCESS_EXIT_CODE;
257}
258

source code of gcc/gencfn-macros.cc