1 | /* Generate from machine description: |
2 | - some #define configuration flags. |
3 | Copyright (C) 1987-2023 Free Software Foundation, Inc. |
4 | |
5 | This file is part of GCC. |
6 | |
7 | GCC is free software; you can redistribute it and/or modify it under |
8 | the terms of the GNU General Public License as published by the Free |
9 | Software Foundation; either version 3, or (at your option) any later |
10 | version. |
11 | |
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
15 | for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. */ |
20 | |
21 | |
22 | #include "bconfig.h" |
23 | #include "system.h" |
24 | #include "coretypes.h" |
25 | #include "tm.h" |
26 | #include "rtl.h" |
27 | #include "errors.h" |
28 | #include "gensupport.h" |
29 | |
30 | |
31 | /* flags to determine output of machine description dependent #define's. */ |
32 | static int max_recog_operands; /* Largest operand number seen. */ |
33 | static int max_dup_operands; /* Largest number of match_dup in any insn. */ |
34 | static int max_clobbers_per_insn; |
35 | static int have_cmove_flag; |
36 | static int have_cond_exec_flag; |
37 | static int have_lo_sum_flag; |
38 | static int have_rotate_flag; |
39 | static int have_rotatert_flag; |
40 | static int have_peephole_flag; |
41 | static int have_peephole2_flag; |
42 | |
43 | /* Maximum number of insns seen in a split. */ |
44 | static int max_insns_per_split = 1; |
45 | |
46 | /* Maximum number of input insns for peephole2. */ |
47 | static int max_insns_per_peep2; |
48 | |
49 | static int clobbers_seen_this_insn; |
50 | static int dup_operands_seen_this_insn; |
51 | |
52 | static void walk_insn_part (rtx, int, int); |
53 | |
54 | /* RECOG_P will be nonzero if this pattern was seen in a context where it will |
55 | be used to recognize, rather than just generate an insn. |
56 | |
57 | NON_PC_SET_SRC will be nonzero if this pattern was seen in a SET_SRC |
58 | of a SET whose destination is not (pc). */ |
59 | |
60 | static void |
61 | walk_insn_part (rtx part, int recog_p, int non_pc_set_src) |
62 | { |
63 | int i, j; |
64 | RTX_CODE code; |
65 | const char *format_ptr; |
66 | |
67 | if (part == 0) |
68 | return; |
69 | |
70 | code = GET_CODE (part); |
71 | switch (code) |
72 | { |
73 | case CLOBBER: |
74 | clobbers_seen_this_insn++; |
75 | break; |
76 | |
77 | case MATCH_OPERAND: |
78 | if (XINT (part, 0) > max_recog_operands) |
79 | max_recog_operands = XINT (part, 0); |
80 | return; |
81 | |
82 | case MATCH_OP_DUP: |
83 | case MATCH_PAR_DUP: |
84 | ++dup_operands_seen_this_insn; |
85 | /* FALLTHRU */ |
86 | case MATCH_SCRATCH: |
87 | case MATCH_PARALLEL: |
88 | case MATCH_OPERATOR: |
89 | if (XINT (part, 0) > max_recog_operands) |
90 | max_recog_operands = XINT (part, 0); |
91 | /* Now scan the rtl's in the vector inside the MATCH_OPERATOR or |
92 | MATCH_PARALLEL. */ |
93 | break; |
94 | |
95 | case LABEL_REF: |
96 | if (GET_CODE (XEXP (part, 0)) == MATCH_OPERAND |
97 | || GET_CODE (XEXP (part, 0)) == MATCH_DUP) |
98 | break; |
99 | return; |
100 | |
101 | case MATCH_DUP: |
102 | ++dup_operands_seen_this_insn; |
103 | if (XINT (part, 0) > max_recog_operands) |
104 | max_recog_operands = XINT (part, 0); |
105 | return; |
106 | |
107 | case LO_SUM: |
108 | if (recog_p) |
109 | have_lo_sum_flag = 1; |
110 | return; |
111 | |
112 | case ROTATE: |
113 | if (recog_p) |
114 | have_rotate_flag = 1; |
115 | return; |
116 | |
117 | case ROTATERT: |
118 | if (recog_p) |
119 | have_rotatert_flag = 1; |
120 | return; |
121 | |
122 | case SET: |
123 | walk_insn_part (SET_DEST (part), recog_p: 0, non_pc_set_src: recog_p); |
124 | walk_insn_part (SET_SRC (part), recog_p, |
125 | GET_CODE (SET_DEST (part)) != PC); |
126 | return; |
127 | |
128 | case IF_THEN_ELSE: |
129 | /* Only consider this machine as having a conditional move if the |
130 | two arms of the IF_THEN_ELSE are both MATCH_OPERAND. Otherwise, |
131 | we have some specific IF_THEN_ELSE construct (like the doz |
132 | instruction on the RS/6000) that can't be used in the general |
133 | context we want it for. */ |
134 | |
135 | if (recog_p && non_pc_set_src |
136 | && GET_CODE (XEXP (part, 1)) == MATCH_OPERAND |
137 | && GET_CODE (XEXP (part, 2)) == MATCH_OPERAND) |
138 | have_cmove_flag = 1; |
139 | break; |
140 | |
141 | case COND_EXEC: |
142 | if (recog_p) |
143 | have_cond_exec_flag = 1; |
144 | break; |
145 | |
146 | case REG: case CONST_INT: case SYMBOL_REF: |
147 | case PC: |
148 | return; |
149 | |
150 | default: |
151 | break; |
152 | } |
153 | |
154 | format_ptr = GET_RTX_FORMAT (GET_CODE (part)); |
155 | |
156 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) |
157 | switch (*format_ptr++) |
158 | { |
159 | case 'e': |
160 | case 'u': |
161 | walk_insn_part (XEXP (part, i), recog_p, non_pc_set_src); |
162 | break; |
163 | case 'E': |
164 | if (XVEC (part, i) != NULL) |
165 | for (j = 0; j < XVECLEN (part, i); j++) |
166 | walk_insn_part (XVECEXP (part, i, j), recog_p, non_pc_set_src); |
167 | break; |
168 | } |
169 | } |
170 | |
171 | static void |
172 | gen_insn (md_rtx_info *info) |
173 | { |
174 | int i; |
175 | |
176 | /* Walk the insn pattern to gather the #define's status. */ |
177 | rtx insn = info->def; |
178 | clobbers_seen_this_insn = 0; |
179 | dup_operands_seen_this_insn = 0; |
180 | if (XVEC (insn, 1) != 0) |
181 | for (i = 0; i < XVECLEN (insn, 1); i++) |
182 | walk_insn_part (XVECEXP (insn, 1, i), recog_p: 1, non_pc_set_src: 0); |
183 | |
184 | if (clobbers_seen_this_insn > max_clobbers_per_insn) |
185 | max_clobbers_per_insn = clobbers_seen_this_insn; |
186 | if (dup_operands_seen_this_insn > max_dup_operands) |
187 | max_dup_operands = dup_operands_seen_this_insn; |
188 | } |
189 | |
190 | /* Similar but scan a define_expand. */ |
191 | |
192 | static void |
193 | gen_expand (md_rtx_info *info) |
194 | { |
195 | int i; |
196 | |
197 | /* Walk the insn pattern to gather the #define's status. */ |
198 | |
199 | /* Note that we don't bother recording the number of MATCH_DUPs |
200 | that occur in a gen_expand, because only reload cares about that. */ |
201 | rtx insn = info->def; |
202 | if (XVEC (insn, 1) != 0) |
203 | for (i = 0; i < XVECLEN (insn, 1); i++) |
204 | { |
205 | /* Compute the maximum SETs and CLOBBERS |
206 | in any one of the sub-insns; |
207 | don't sum across all of them. */ |
208 | clobbers_seen_this_insn = 0; |
209 | |
210 | walk_insn_part (XVECEXP (insn, 1, i), recog_p: 0, non_pc_set_src: 0); |
211 | |
212 | if (clobbers_seen_this_insn > max_clobbers_per_insn) |
213 | max_clobbers_per_insn = clobbers_seen_this_insn; |
214 | } |
215 | } |
216 | |
217 | /* Similar but scan a define_split. */ |
218 | |
219 | static void |
220 | gen_split (md_rtx_info *info) |
221 | { |
222 | int i; |
223 | |
224 | /* Look through the patterns that are matched |
225 | to compute the maximum operand number. */ |
226 | rtx split = info->def; |
227 | for (i = 0; i < XVECLEN (split, 0); i++) |
228 | walk_insn_part (XVECEXP (split, 0, i), recog_p: 1, non_pc_set_src: 0); |
229 | /* Look at the number of insns this insn could split into. */ |
230 | if (XVECLEN (split, 2) > max_insns_per_split) |
231 | max_insns_per_split = XVECLEN (split, 2); |
232 | } |
233 | |
234 | static void |
235 | gen_peephole (md_rtx_info *info) |
236 | { |
237 | int i; |
238 | |
239 | /* Look through the patterns that are matched |
240 | to compute the maximum operand number. */ |
241 | rtx peep = info->def; |
242 | for (i = 0; i < XVECLEN (peep, 0); i++) |
243 | walk_insn_part (XVECEXP (peep, 0, i), recog_p: 1, non_pc_set_src: 0); |
244 | } |
245 | |
246 | static void |
247 | gen_peephole2 (md_rtx_info *info) |
248 | { |
249 | int i, n; |
250 | |
251 | /* Look through the patterns that are matched |
252 | to compute the maximum operand number. */ |
253 | rtx peep = info->def; |
254 | for (i = XVECLEN (peep, 0) - 1; i >= 0; --i) |
255 | walk_insn_part (XVECEXP (peep, 0, i), recog_p: 1, non_pc_set_src: 0); |
256 | |
257 | /* Look at the number of insns this insn can be matched from. */ |
258 | for (i = XVECLEN (peep, 0) - 1, n = 0; i >= 0; --i) |
259 | if (GET_CODE (XVECEXP (peep, 0, i)) != MATCH_DUP |
260 | && GET_CODE (XVECEXP (peep, 0, i)) != MATCH_SCRATCH) |
261 | n++; |
262 | if (n > max_insns_per_peep2) |
263 | max_insns_per_peep2 = n; |
264 | } |
265 | |
266 | int |
267 | main (int argc, const char **argv) |
268 | { |
269 | progname = "genconfig" ; |
270 | |
271 | if (!init_rtx_reader_args (argc, argv)) |
272 | return (FATAL_EXIT_CODE); |
273 | |
274 | puts (s: "/* Generated automatically by the program `genconfig'" ); |
275 | puts (s: " from the machine description file `md'. */\n" ); |
276 | puts (s: "#ifndef GCC_INSN_CONFIG_H" ); |
277 | puts (s: "#define GCC_INSN_CONFIG_H\n" ); |
278 | |
279 | /* Allow at least 30 operands for the sake of asm constructs. */ |
280 | /* ??? We *really* ought to reorganize things such that there |
281 | is no fixed upper bound. */ |
282 | max_recog_operands = 29; /* We will add 1 later. */ |
283 | max_dup_operands = 1; |
284 | |
285 | /* Read the machine description. */ |
286 | |
287 | md_rtx_info info; |
288 | while (read_md_rtx (&info)) |
289 | switch (GET_CODE (info.def)) |
290 | { |
291 | case DEFINE_INSN: |
292 | gen_insn (info: &info); |
293 | break; |
294 | |
295 | case DEFINE_EXPAND: |
296 | gen_expand (info: &info); |
297 | break; |
298 | |
299 | case DEFINE_SPLIT: |
300 | gen_split (info: &info); |
301 | break; |
302 | |
303 | case DEFINE_PEEPHOLE2: |
304 | have_peephole2_flag = 1; |
305 | gen_peephole2 (info: &info); |
306 | break; |
307 | |
308 | case DEFINE_PEEPHOLE: |
309 | have_peephole_flag = 1; |
310 | gen_peephole (info: &info); |
311 | break; |
312 | |
313 | default: |
314 | break; |
315 | } |
316 | |
317 | printf (format: "#define MAX_RECOG_OPERANDS %d\n" , max_recog_operands + 1); |
318 | printf (format: "#define MAX_DUP_OPERANDS %d\n" , max_dup_operands); |
319 | |
320 | /* This is conditionally defined, in case the user writes code which emits |
321 | more splits than we can readily see (and knows s/he does it). */ |
322 | printf (format: "#ifndef MAX_INSNS_PER_SPLIT\n" ); |
323 | printf (format: "#define MAX_INSNS_PER_SPLIT %d\n" , max_insns_per_split); |
324 | printf (format: "#endif\n" ); |
325 | |
326 | if (have_cmove_flag) |
327 | printf (format: "#define HAVE_conditional_move 1\n" ); |
328 | else |
329 | printf (format: "#define HAVE_conditional_move 0\n" ); |
330 | |
331 | if (have_cond_exec_flag) |
332 | printf (format: "#define HAVE_conditional_execution 1\n" ); |
333 | else |
334 | printf (format: "#define HAVE_conditional_execution 0\n" ); |
335 | |
336 | if (have_lo_sum_flag) |
337 | printf (format: "#define HAVE_lo_sum 1\n" ); |
338 | else |
339 | printf (format: "#define HAVE_lo_sum 0\n" ); |
340 | |
341 | if (have_rotate_flag) |
342 | printf (format: "#define HAVE_rotate 1\n" ); |
343 | |
344 | if (have_rotatert_flag) |
345 | printf (format: "#define HAVE_rotatert 1\n" ); |
346 | |
347 | if (have_peephole_flag) |
348 | printf (format: "#define HAVE_peephole 1\n" ); |
349 | else |
350 | printf (format: "#define HAVE_peephole 0\n" ); |
351 | |
352 | if (have_peephole2_flag) |
353 | { |
354 | printf (format: "#define HAVE_peephole2 1\n" ); |
355 | printf (format: "#define MAX_INSNS_PER_PEEP2 %d\n" , max_insns_per_peep2); |
356 | } |
357 | else |
358 | { |
359 | printf (format: "#define HAVE_peephole2 0\n" ); |
360 | printf (format: "#define MAX_INSNS_PER_PEEP2 0\n" ); |
361 | } |
362 | |
363 | puts (s: "\n#endif /* GCC_INSN_CONFIG_H */" ); |
364 | |
365 | if (ferror (stdout) || fflush (stdout) || fclose (stdout)) |
366 | return FATAL_EXIT_CODE; |
367 | |
368 | return SUCCESS_EXIT_CODE; |
369 | } |
370 | |