1 | /* Generate code to allocate RTL structures. |
2 | Copyright (C) 1997-2024 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 | |
21 | #include "bconfig.h" |
22 | #include "system.h" |
23 | |
24 | struct rtx_definition |
25 | { |
26 | const char *const enumname, *const name, *const format; |
27 | }; |
28 | |
29 | /* rtl.def needs CONST_DOUBLE_FORMAT, but we don't care what |
30 | CONST_DOUBLE_FORMAT is because we're not going to be generating |
31 | anything for CONST_DOUBLE anyway. */ |
32 | #define CONST_DOUBLE_FORMAT "" |
33 | |
34 | #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) { #ENUM, NAME, FORMAT }, |
35 | |
36 | static const struct rtx_definition defs[] = |
37 | { |
38 | #include "rtl.def" /* rtl expressions are documented here */ |
39 | }; |
40 | #define NUM_RTX_CODE ARRAY_SIZE (defs) |
41 | |
42 | static const char *formats[NUM_RTX_CODE]; |
43 | |
44 | /* Decode a format letter into a C type string. */ |
45 | |
46 | static const char * |
47 | type_from_format (int c) |
48 | { |
49 | switch (c) |
50 | { |
51 | case 'i': |
52 | return "int " ; |
53 | |
54 | case 'w': |
55 | return "HOST_WIDE_INT " ; |
56 | |
57 | case 'p': |
58 | return "poly_uint16 " ; |
59 | |
60 | case 's': |
61 | return "const char *" ; |
62 | |
63 | case 'e': case 'u': |
64 | return "rtx " ; |
65 | |
66 | case 'E': |
67 | return "rtvec " ; |
68 | case 't': |
69 | return "tree " ; |
70 | case 'B': |
71 | return "basic_block " ; |
72 | default: |
73 | gcc_unreachable (); |
74 | } |
75 | } |
76 | |
77 | /* Decode a format letter into the proper accessor function. */ |
78 | |
79 | static const char * |
80 | accessor_from_format (int c) |
81 | { |
82 | switch (c) |
83 | { |
84 | case 'i': |
85 | return "XINT" ; |
86 | |
87 | case 'w': |
88 | return "XWINT" ; |
89 | |
90 | case 's': |
91 | return "XSTR" ; |
92 | |
93 | case 'e': case 'u': |
94 | return "XEXP" ; |
95 | |
96 | case 'E': |
97 | return "XVEC" ; |
98 | |
99 | case 't': |
100 | return "XTREE" ; |
101 | |
102 | case 'B': |
103 | return "XBBDEF" ; |
104 | |
105 | default: |
106 | gcc_unreachable (); |
107 | } |
108 | } |
109 | |
110 | /* Return nonzero if we should ignore FMT, an RTL format, when making |
111 | the list of formats we write routines to create. */ |
112 | |
113 | static int |
114 | special_format (const char *fmt) |
115 | { |
116 | return (strchr (s: fmt, c: '*') != 0 |
117 | || strchr (s: fmt, c: 'V') != 0 |
118 | || strchr (s: fmt, c: 'S') != 0 |
119 | || strchr (s: fmt, c: 'n') != 0 |
120 | || strchr (s: fmt, c: 'r') != 0); |
121 | } |
122 | |
123 | /* Return true if CODE always has VOIDmode. */ |
124 | |
125 | static inline bool |
126 | always_void_p (int idx) |
127 | { |
128 | return strcmp (s1: defs[idx].enumname, s2: "SET" ) == 0; |
129 | } |
130 | |
131 | /* Return nonzero if the RTL code given by index IDX is one that we should |
132 | generate a gen_rtx_raw_FOO macro for, not gen_rtx_FOO (because gen_rtx_FOO |
133 | is a wrapper in emit-rtl.cc). */ |
134 | |
135 | static int |
136 | special_rtx (int idx) |
137 | { |
138 | return (strcmp (s1: defs[idx].enumname, s2: "EXPR_LIST" ) == 0 |
139 | || strcmp (s1: defs[idx].enumname, s2: "INSN_LIST" ) == 0 |
140 | || strcmp (s1: defs[idx].enumname, s2: "INSN" ) == 0 |
141 | || strcmp (s1: defs[idx].enumname, s2: "CONST_INT" ) == 0 |
142 | || strcmp (s1: defs[idx].enumname, s2: "REG" ) == 0 |
143 | || strcmp (s1: defs[idx].enumname, s2: "SUBREG" ) == 0 |
144 | || strcmp (s1: defs[idx].enumname, s2: "MEM" ) == 0 |
145 | || strcmp (s1: defs[idx].enumname, s2: "PC" ) == 0 |
146 | || strcmp (s1: defs[idx].enumname, s2: "RETURN" ) == 0 |
147 | || strcmp (s1: defs[idx].enumname, s2: "SIMPLE_RETURN" ) == 0 |
148 | || strcmp (s1: defs[idx].enumname, s2: "CONST_VECTOR" ) == 0); |
149 | } |
150 | |
151 | /* Return nonzero if the RTL code given by index IDX is one that we should |
152 | generate no macro for at all (because gen_rtx_FOO is never used or |
153 | cannot have the obvious interface). */ |
154 | |
155 | static int |
156 | excluded_rtx (int idx) |
157 | { |
158 | return (strcmp (s1: defs[idx].enumname, s2: "VAR_LOCATION" ) == 0 |
159 | || strcmp (s1: defs[idx].enumname, s2: "CONST_DOUBLE" ) == 0 |
160 | || strcmp (s1: defs[idx].enumname, s2: "CONST_WIDE_INT" ) == 0 |
161 | || strcmp (s1: defs[idx].enumname, s2: "CONST_POLY_INT" ) == 0 |
162 | || strcmp (s1: defs[idx].enumname, s2: "CONST_FIXED" ) == 0); |
163 | } |
164 | |
165 | /* Place a list of all format specifiers we use into the array FORMAT. */ |
166 | |
167 | static void |
168 | find_formats (void) |
169 | { |
170 | unsigned int i; |
171 | |
172 | for (i = 0; i < NUM_RTX_CODE; i++) |
173 | { |
174 | const char **f; |
175 | |
176 | if (special_format (fmt: defs[i].format)) |
177 | continue; |
178 | |
179 | for (f = formats; *f; f++) |
180 | if (! strcmp (s1: *f, s2: defs[i].format)) |
181 | break; |
182 | |
183 | if (*f == 0) |
184 | *f = defs[i].format; |
185 | } |
186 | } |
187 | |
188 | |
189 | /* Generate macros to generate RTL of code IDX using the functions we |
190 | write. */ |
191 | |
192 | static void |
193 | genmacro (int idx) |
194 | { |
195 | const char *p; |
196 | const char *sep = "" ; |
197 | int i; |
198 | |
199 | /* We write a macro that defines gen_rtx_RTLCODE to be an equivalent to |
200 | gen_rtx_fmt_FORMAT where FORMAT is the RTX_FORMAT of RTLCODE. */ |
201 | |
202 | if (excluded_rtx (idx)) |
203 | /* Don't define a macro for this code. */ |
204 | return; |
205 | |
206 | bool has_mode_p = !always_void_p (idx); |
207 | printf (format: "#define gen_rtx_%s%s(" , |
208 | special_rtx (idx) ? "raw_" : "" , defs[idx].enumname); |
209 | if (has_mode_p) |
210 | { |
211 | printf (format: "MODE" ); |
212 | sep = ", " ; |
213 | } |
214 | |
215 | for (p = defs[idx].format, i = 0; *p != 0; p++) |
216 | if (*p != '0') |
217 | { |
218 | printf (format: "%sARG%d" , sep, i++); |
219 | sep = ", " ; |
220 | } |
221 | |
222 | printf (format: ") \\\n gen_rtx_fmt_%s (%s, %s" , |
223 | defs[idx].format, defs[idx].enumname, |
224 | has_mode_p ? "(MODE)" : "VOIDmode" ); |
225 | |
226 | for (p = defs[idx].format, i = 0; *p != 0; p++) |
227 | if (*p != '0') |
228 | printf (format: ", (ARG%d)" , i++); |
229 | |
230 | puts (s: ")" ); |
231 | } |
232 | |
233 | /* Generate the code for functions to generate RTL whose format is FORMAT. */ |
234 | |
235 | static void |
236 | gendef (const char *format) |
237 | { |
238 | const char *p; |
239 | int i, j; |
240 | |
241 | /* Write the definition of the init function name and the types |
242 | of the arguments. */ |
243 | |
244 | puts (s: "static inline rtx" ); |
245 | printf (format: "init_rtx_fmt_%s (rtx rt, machine_mode mode" , format); |
246 | for (p = format, i = 0; *p != 0; p++) |
247 | if (*p != '0') |
248 | printf (format: ",\n\t%sarg%d" , type_from_format (c: *p), i++); |
249 | puts (s: ")" ); |
250 | |
251 | /* Now write out the body of the init function itself. */ |
252 | puts (s: "{" ); |
253 | puts (s: " PUT_MODE_RAW (rt, mode);" ); |
254 | |
255 | for (p = format, i = j = 0; *p ; ++p, ++i) |
256 | if (*p == '0') |
257 | printf (format: " X0EXP (rt, %d) = NULL_RTX;\n" , i); |
258 | else if (*p == 'p') |
259 | printf (format: " SUBREG_BYTE (rt) = arg%d;\n" , j++); |
260 | else |
261 | printf (format: " %s (rt, %d) = arg%d;\n" , accessor_from_format (c: *p), i, j++); |
262 | |
263 | puts (s: " return rt;\n}\n" ); |
264 | |
265 | /* Write the definition of the gen function name and the types |
266 | of the arguments. */ |
267 | |
268 | puts (s: "static inline rtx" ); |
269 | printf (format: "gen_rtx_fmt_%s_stat (RTX_CODE code, machine_mode mode" , format); |
270 | for (p = format, i = 0; *p != 0; p++) |
271 | if (*p != '0') |
272 | printf (format: ",\n\t%sarg%d" , type_from_format (c: *p), i++); |
273 | puts (s: " MEM_STAT_DECL)" ); |
274 | |
275 | /* Now write out the body of the function itself, which allocates |
276 | the memory and initializes it. */ |
277 | puts (s: "{" ); |
278 | puts (s: " rtx rt;\n" ); |
279 | |
280 | puts (s: " rt = rtx_alloc (code PASS_MEM_STAT);" ); |
281 | printf (format: " return init_rtx_fmt_%s (rt, mode" , format); |
282 | for (p = format, i = 0; *p != 0; p++) |
283 | if (*p != '0') |
284 | printf (format: ", arg%d" , i++); |
285 | puts (s: ");\n}\n" ); |
286 | |
287 | /* Write the definition of gen macro. */ |
288 | |
289 | printf (format: "#define gen_rtx_fmt_%s(c, m" , format); |
290 | for (p = format, i = 0; *p != 0; p++) |
291 | if (*p != '0') |
292 | printf (format: ", arg%d" , i++); |
293 | printf (format: ") \\\n gen_rtx_fmt_%s_stat ((c), (m)" , format); |
294 | for (p = format, i = 0; *p != 0; p++) |
295 | if (*p != '0') |
296 | printf (format: ", (arg%d)" , i++); |
297 | printf (format: " MEM_STAT_INFO)\n\n" ); |
298 | |
299 | /* Write the definition of alloca macro. */ |
300 | |
301 | printf (format: "#define alloca_rtx_fmt_%s(c, m" , format); |
302 | for (p = format, i = 0; *p != 0; p++) |
303 | if (*p != '0') |
304 | printf (format: ", arg%d" , i++); |
305 | printf (format: ") \\\n init_rtx_fmt_%s (rtx_alloca ((c)), (m)" , format); |
306 | for (p = format, i = 0; *p != 0; p++) |
307 | if (*p != '0') |
308 | printf (format: ", (arg%d)" , i++); |
309 | printf (format: ")\n\n" ); |
310 | } |
311 | |
312 | /* Generate the documentation header for files we write. */ |
313 | |
314 | static void |
315 | genlegend (void) |
316 | { |
317 | puts (s: "/* Generated automatically by gengenrtl from rtl.def. */\n" ); |
318 | } |
319 | |
320 | /* Generate the text of the header file we make, genrtl.h. */ |
321 | |
322 | static void |
323 | (void) |
324 | { |
325 | unsigned int i; |
326 | const char **fmt; |
327 | |
328 | puts (s: "#ifndef GCC_GENRTL_H" ); |
329 | puts (s: "#define GCC_GENRTL_H\n" ); |
330 | puts (s: "#include \"statistics.h\"\n" ); |
331 | |
332 | for (fmt = formats; *fmt; ++fmt) |
333 | gendef (format: *fmt); |
334 | |
335 | putchar ('\n'); |
336 | |
337 | for (i = 0; i < NUM_RTX_CODE; i++) |
338 | if (! special_format (fmt: defs[i].format)) |
339 | genmacro (idx: i); |
340 | |
341 | puts (s: "\n#endif /* GCC_GENRTL_H */" ); |
342 | } |
343 | |
344 | /* This is the main program. */ |
345 | |
346 | int |
347 | main (void) |
348 | { |
349 | find_formats (); |
350 | genlegend (); |
351 | |
352 | genheader (); |
353 | |
354 | if (ferror (stdout) || fflush (stdout) || fclose (stdout)) |
355 | return FATAL_EXIT_CODE; |
356 | |
357 | return SUCCESS_EXIT_CODE; |
358 | } |
359 | |