1 | /* Generate macros based on the combined_fn enum. |
2 | Copyright (C) 2015-2023 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free |
8 | Software Foundation; either version 3, or (at your option) any later |
9 | version. |
10 | |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along 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 | |
72 | typedef hash_set <nofree_string_hash> string_set; |
73 | |
74 | /* Add all names in null-terminated list NAMES to SET. */ |
75 | |
76 | static void |
77 | add_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 | |
86 | static bool |
87 | is_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 | |
102 | static void |
103 | print_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 | |
122 | static void |
123 | print_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 | |
136 | const 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 | |
143 | const 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 | |
150 | const 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 | |
157 | static const char *const flt_suffixes[] = { "F" , "" , "L" , NULL }; |
158 | static const char *const fltfn_suffixes[] = { "F16" , "F32" , "F64" , "F128" , |
159 | "F32X" , "F64X" , "F128X" , NULL }; |
160 | static const char *const fltall_suffixes[] = { "F" , "" , "L" , "F16" , "F32" , |
161 | "F64" , "F128" , "F32X" , "F64X" , |
162 | "F128X" , NULL }; |
163 | static const char *const int_suffixes[] = { "" , "L" , "LL" , "IMAX" , NULL }; |
164 | |
165 | static const char *const *const suffix_lists[] = { |
166 | flt_suffixes, |
167 | int_suffixes, |
168 | NULL |
169 | }; |
170 | |
171 | int |
172 | main (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 | |