1 | /* Generate attribute information (insn-attr.h) from machine description. |
2 | Copyright (C) 1991-2023 Free Software Foundation, Inc. |
3 | Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) |
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 "read-md.h" |
29 | #include "gensupport.h" |
30 | |
31 | |
32 | static vec<rtx> const_attrs, reservations; |
33 | |
34 | |
35 | static void |
36 | gen_attr (md_rtx_info *info) |
37 | { |
38 | const char *p; |
39 | rtx attr = info->def; |
40 | int is_const = GET_CODE (XEXP (attr, 2)) == CONST; |
41 | |
42 | if (is_const) |
43 | const_attrs.safe_push (obj: attr); |
44 | |
45 | printf (format: "#define HAVE_ATTR_%s 1\n" , XSTR (attr, 0)); |
46 | |
47 | /* If numeric attribute, don't need to write an enum. */ |
48 | if (GET_CODE (attr) == DEFINE_ENUM_ATTR) |
49 | printf (format: "extern enum %s get_attr_%s (%s);\n\n" , |
50 | XSTR (attr, 1), XSTR (attr, 0), |
51 | (is_const ? "void" : "rtx_insn *" )); |
52 | else |
53 | { |
54 | p = XSTR (attr, 1); |
55 | if (*p == '\0') |
56 | printf (format: "extern int get_attr_%s (%s);\n" , XSTR (attr, 0), |
57 | (is_const ? "void" : "rtx_insn *" )); |
58 | else |
59 | printf (format: "extern enum attr_%s get_attr_%s (%s);\n\n" , |
60 | XSTR (attr, 0), XSTR (attr, 0), |
61 | (is_const ? "void" : "rtx_insn *" )); |
62 | } |
63 | |
64 | /* If `length' attribute, write additional function definitions and define |
65 | variables used by `insn_current_length'. */ |
66 | if (! strcmp (XSTR (attr, 0), s2: "length" )) |
67 | { |
68 | puts (s: "\ |
69 | extern void shorten_branches (rtx_insn *);\n\ |
70 | extern int insn_default_length (rtx_insn *);\n\ |
71 | extern int insn_min_length (rtx_insn *);\n\ |
72 | extern int insn_variable_length_p (rtx_insn *);\n\ |
73 | extern int insn_current_length (rtx_insn *);\n\n\ |
74 | #include \"insn-addr.h\"\n" ); |
75 | } |
76 | } |
77 | |
78 | /* Check that attribute NAME is used in define_insn_reservation condition |
79 | EXP. Return true if it is. */ |
80 | static bool |
81 | check_tune_attr (const char *name, rtx exp) |
82 | { |
83 | switch (GET_CODE (exp)) |
84 | { |
85 | case AND: |
86 | if (check_tune_attr (name, XEXP (exp, 0))) |
87 | return true; |
88 | return check_tune_attr (name, XEXP (exp, 1)); |
89 | |
90 | case IOR: |
91 | return (check_tune_attr (name, XEXP (exp, 0)) |
92 | && check_tune_attr (name, XEXP (exp, 1))); |
93 | |
94 | case EQ_ATTR: |
95 | return strcmp (XSTR (exp, 0), s2: name) == 0; |
96 | |
97 | default: |
98 | return false; |
99 | } |
100 | } |
101 | |
102 | /* Try to find a const attribute (usually cpu or tune) that is used |
103 | in all define_insn_reservation conditions. */ |
104 | static bool |
105 | find_tune_attr (rtx exp) |
106 | { |
107 | unsigned int i; |
108 | rtx attr; |
109 | |
110 | switch (GET_CODE (exp)) |
111 | { |
112 | case AND: |
113 | case IOR: |
114 | if (find_tune_attr (XEXP (exp, 0))) |
115 | return true; |
116 | return find_tune_attr (XEXP (exp, 1)); |
117 | |
118 | case EQ_ATTR: |
119 | if (strcmp (XSTR (exp, 0), s2: "alternative" ) == 0) |
120 | return false; |
121 | |
122 | FOR_EACH_VEC_ELT (const_attrs, i, attr) |
123 | if (strcmp (XSTR (attr, 0), XSTR (exp, 0)) == 0) |
124 | { |
125 | unsigned int j; |
126 | rtx resv; |
127 | |
128 | FOR_EACH_VEC_ELT (reservations, j, resv) |
129 | if (! check_tune_attr (XSTR (attr, 0), XEXP (resv, 2))) |
130 | return false; |
131 | return true; |
132 | } |
133 | return false; |
134 | |
135 | default: |
136 | return false; |
137 | } |
138 | } |
139 | |
140 | int |
141 | main (int argc, const char **argv) |
142 | { |
143 | bool have_annul_true = false; |
144 | bool have_annul_false = false; |
145 | int num_insn_reservations = 0; |
146 | int i; |
147 | |
148 | progname = "genattr" ; |
149 | |
150 | if (!init_rtx_reader_args (argc, argv)) |
151 | return (FATAL_EXIT_CODE); |
152 | |
153 | puts (s: "/* Generated automatically by the program `genattr'" ); |
154 | puts (s: " from the machine description file `md'. */\n" ); |
155 | puts (s: "#ifndef GCC_INSN_ATTR_H" ); |
156 | puts (s: "#define GCC_INSN_ATTR_H\n" ); |
157 | |
158 | puts (s: "#include \"insn-attr-common.h\"\n" ); |
159 | |
160 | /* Read the machine description. */ |
161 | |
162 | md_rtx_info info; |
163 | while (read_md_rtx (&info)) |
164 | { |
165 | rtx def = info.def; |
166 | switch (GET_CODE (def)) |
167 | { |
168 | case DEFINE_ATTR: |
169 | case DEFINE_ENUM_ATTR: |
170 | gen_attr (info: &info); |
171 | break; |
172 | |
173 | case DEFINE_DELAY: |
174 | for (i = 0; i < XVECLEN (def, 1); i += 3) |
175 | { |
176 | if (XVECEXP (def, 1, i + 1)) |
177 | have_annul_true = true; |
178 | |
179 | if (XVECEXP (def, 1, i + 2)) |
180 | have_annul_false = true; |
181 | } |
182 | break; |
183 | |
184 | case DEFINE_INSN_RESERVATION: |
185 | num_insn_reservations++; |
186 | reservations.safe_push (obj: def); |
187 | break; |
188 | |
189 | default: |
190 | break; |
191 | } |
192 | } |
193 | |
194 | printf (format: "extern int num_delay_slots (rtx_insn *);\n" ); |
195 | printf (format: "extern int eligible_for_delay (rtx_insn *, int, rtx_insn *, int);\n\n" ); |
196 | printf (format: "extern int const_num_delay_slots (rtx_insn *);\n\n" ); |
197 | printf (format: "#define ANNUL_IFTRUE_SLOTS %d\n" , have_annul_true); |
198 | printf (format: "extern int eligible_for_annul_true (rtx_insn *, int, rtx_insn *, int);\n" ); |
199 | printf (format: "#define ANNUL_IFFALSE_SLOTS %d\n" , have_annul_false); |
200 | printf (format: "extern int eligible_for_annul_false (rtx_insn *, int, rtx_insn *, int);\n" ); |
201 | |
202 | if (num_insn_reservations > 0) |
203 | { |
204 | bool has_tune_attr |
205 | = find_tune_attr (XEXP (reservations[0], 2)); |
206 | /* Output interface for pipeline hazards recognition based on |
207 | DFA (deterministic finite state automata. */ |
208 | printf (format: "\n/* DFA based pipeline interface. */" ); |
209 | printf (format: "\n#ifndef AUTOMATON_ALTS\n" ); |
210 | printf (format: "#define AUTOMATON_ALTS 0\n" ); |
211 | printf (format: "#endif\n\n" ); |
212 | printf (format: "\n#ifndef AUTOMATON_STATE_ALTS\n" ); |
213 | printf (format: "#define AUTOMATON_STATE_ALTS 0\n" ); |
214 | printf (format: "#endif\n\n" ); |
215 | printf (format: "#ifndef CPU_UNITS_QUERY\n" ); |
216 | printf (format: "#define CPU_UNITS_QUERY 0\n" ); |
217 | printf (format: "#endif\n\n" ); |
218 | /* Interface itself: */ |
219 | if (has_tune_attr) |
220 | { |
221 | printf (format: "/* Initialize fn pointers for internal_dfa_insn_code\n" ); |
222 | printf (format: " and insn_default_latency. */\n" ); |
223 | printf (format: "extern void init_sched_attrs (void);\n\n" ); |
224 | printf (format: "/* Internal insn code number used by automata. */\n" ); |
225 | printf (format: "extern int (*internal_dfa_insn_code) (rtx_insn *);\n\n" ); |
226 | printf (format: "/* Insn latency time defined in define_insn_reservation. */\n" ); |
227 | printf (format: "extern int (*insn_default_latency) (rtx_insn *);\n\n" ); |
228 | } |
229 | else |
230 | { |
231 | printf (format: "#define init_sched_attrs() do { } while (0)\n\n" ); |
232 | printf (format: "/* Internal insn code number used by automata. */\n" ); |
233 | printf (format: "extern int internal_dfa_insn_code (rtx_insn *);\n\n" ); |
234 | printf (format: "/* Insn latency time defined in define_insn_reservation. */\n" ); |
235 | printf (format: "extern int insn_default_latency (rtx_insn *);\n\n" ); |
236 | } |
237 | printf (format: "/* Return nonzero if there is a bypass for given insn\n" ); |
238 | printf (format: " which is a data producer. */\n" ); |
239 | printf (format: "extern int bypass_p (rtx_insn *);\n\n" ); |
240 | printf (format: "/* Insn latency time on data consumed by the 2nd insn.\n" ); |
241 | printf (format: " Use the function if bypass_p returns nonzero for\n" ); |
242 | printf (format: " the 1st insn. */\n" ); |
243 | printf (format: "extern int insn_latency (rtx_insn *, rtx_insn *);\n\n" ); |
244 | printf (format: "/* Maximal insn latency time possible of all bypasses for this insn.\n" ); |
245 | printf (format: " Use the function if bypass_p returns nonzero for\n" ); |
246 | printf (format: " the 1st insn. */\n" ); |
247 | printf (format: "extern int maximal_insn_latency (rtx_insn *);\n\n" ); |
248 | printf (format: "\n#if AUTOMATON_ALTS\n" ); |
249 | printf (format: "/* The following function returns number of alternative\n" ); |
250 | printf (format: " reservations of given insn. It may be used for better\n" ); |
251 | printf (format: " insns scheduling heuristics. */\n" ); |
252 | printf (format: "extern int insn_alts (rtx);\n\n" ); |
253 | printf (format: "#endif\n\n" ); |
254 | printf (format: "/* Maximal possible number of insns waiting results being\n" ); |
255 | printf (format: " produced by insns whose execution is not finished. */\n" ); |
256 | printf (format: "extern const int max_insn_queue_index;\n\n" ); |
257 | printf (format: "/* Pointer to data describing current state of DFA. */\n" ); |
258 | printf (format: "typedef void *state_t;\n\n" ); |
259 | printf (format: "/* Size of the data in bytes. */\n" ); |
260 | printf (format: "extern int state_size (void);\n\n" ); |
261 | printf (format: "/* Initiate given DFA state, i.e. Set up the state\n" ); |
262 | printf (format: " as all functional units were not reserved. */\n" ); |
263 | printf (format: "extern void state_reset (state_t);\n" ); |
264 | printf (format: "/* The following function returns negative value if given\n" ); |
265 | printf (format: " insn can be issued in processor state described by given\n" ); |
266 | printf (format: " DFA state. In this case, the DFA state is changed to\n" ); |
267 | printf (format: " reflect the current and future reservations by given\n" ); |
268 | printf (format: " insn. Otherwise the function returns minimal time\n" ); |
269 | printf (format: " delay to issue the insn. This delay may be zero\n" ); |
270 | printf (format: " for superscalar or VLIW processors. If the second\n" ); |
271 | printf (format: " parameter is NULL the function changes given DFA state\n" ); |
272 | printf (format: " as new processor cycle started. */\n" ); |
273 | printf (format: "extern int state_transition (state_t, rtx);\n" ); |
274 | printf (format: "\n#if AUTOMATON_STATE_ALTS\n" ); |
275 | printf (format: "/* The following function returns number of possible\n" ); |
276 | printf (format: " alternative reservations of given insn in given\n" ); |
277 | printf (format: " DFA state. It may be used for better insns scheduling\n" ); |
278 | printf (format: " heuristics. By default the function is defined if\n" ); |
279 | printf (format: " macro AUTOMATON_STATE_ALTS is defined because its\n" ); |
280 | printf (format: " implementation may require much memory. */\n" ); |
281 | printf (format: "extern int state_alts (state_t, rtx);\n" ); |
282 | printf (format: "#endif\n\n" ); |
283 | printf (format: "extern int min_issue_delay (state_t, rtx_insn *);\n" ); |
284 | printf (format: "/* The following function returns nonzero if no one insn\n" ); |
285 | printf (format: " can be issued in current DFA state. */\n" ); |
286 | printf (format: "extern int state_dead_lock_p (state_t);\n" ); |
287 | printf (format: "/* The function returns minimal delay of issue of the 2nd\n" ); |
288 | printf (format: " insn after issuing the 1st insn in given DFA state.\n" ); |
289 | printf (format: " The 1st insn should be issued in given state (i.e.\n" ); |
290 | printf (format: " state_transition should return negative value for\n" ); |
291 | printf (format: " the insn and the state). Data dependencies between\n" ); |
292 | printf (format: " the insns are ignored by the function. */\n" ); |
293 | printf (format: "extern int " |
294 | "min_insn_conflict_delay (state_t, rtx_insn *, rtx_insn *);\n" ); |
295 | printf (format: "/* The following function outputs reservations for given\n" ); |
296 | printf (format: " insn as they are described in the corresponding\n" ); |
297 | printf (format: " define_insn_reservation. */\n" ); |
298 | printf (format: "extern void print_reservation (FILE *, rtx_insn *);\n" ); |
299 | printf (format: "\n#if CPU_UNITS_QUERY\n" ); |
300 | printf (format: "/* The following function returns code of functional unit\n" ); |
301 | printf (format: " with given name (see define_cpu_unit). */\n" ); |
302 | printf (format: "extern int get_cpu_unit_code (const char *);\n" ); |
303 | printf (format: "/* The following function returns nonzero if functional\n" ); |
304 | printf (format: " unit with given code is currently reserved in given\n" ); |
305 | printf (format: " DFA state. */\n" ); |
306 | printf (format: "extern int cpu_unit_reservation_p (state_t, int);\n" ); |
307 | printf (format: "#endif\n\n" ); |
308 | printf (format: "/* The following function returns true if insn\n" ); |
309 | printf (format: " has a dfa reservation. */\n" ); |
310 | printf (format: "extern bool insn_has_dfa_reservation_p (rtx_insn *);\n\n" ); |
311 | printf (format: "/* Clean insn code cache. It should be called if there\n" ); |
312 | printf (format: " is a chance that condition value in a\n" ); |
313 | printf (format: " define_insn_reservation will be changed after\n" ); |
314 | printf (format: " last call of dfa_start. */\n" ); |
315 | printf (format: "extern void dfa_clean_insn_cache (void);\n\n" ); |
316 | printf (format: "extern void dfa_clear_single_insn_cache (rtx_insn *);\n\n" ); |
317 | printf (format: "/* Initiate and finish work with DFA. They should be\n" ); |
318 | printf (format: " called as the first and the last interface\n" ); |
319 | printf (format: " functions. */\n" ); |
320 | printf (format: "extern void dfa_start (void);\n" ); |
321 | printf (format: "extern void dfa_finish (void);\n" ); |
322 | } |
323 | else |
324 | { |
325 | /* Otherwise we do no scheduling, but we need these typedefs |
326 | in order to avoid uglifying other code with more ifdefs. */ |
327 | printf (format: "typedef void *state_t;\n\n" ); |
328 | } |
329 | |
330 | /* Special-purpose attributes should be tested with if, not #ifdef. */ |
331 | const char * const special_attrs[] = { "length" , "enabled" , |
332 | "preferred_for_size" , |
333 | "preferred_for_speed" , 0 }; |
334 | for (const char * const *p = special_attrs; *p; p++) |
335 | { |
336 | printf (format: "#ifndef HAVE_ATTR_%s\n" |
337 | "#define HAVE_ATTR_%s 0\n" |
338 | "#endif\n" , *p, *p); |
339 | } |
340 | /* We make an exception here to provide stub definitions for |
341 | insn_*_length* / get_attr_enabled functions. */ |
342 | puts (s: "#if !HAVE_ATTR_length\n" |
343 | "extern int hook_int_rtx_insn_unreachable (rtx_insn *);\n" |
344 | "#define insn_default_length hook_int_rtx_insn_unreachable\n" |
345 | "#define insn_min_length hook_int_rtx_insn_unreachable\n" |
346 | "#define insn_variable_length_p hook_int_rtx_insn_unreachable\n" |
347 | "#define insn_current_length hook_int_rtx_insn_unreachable\n" |
348 | "#include \"insn-addr.h\"\n" |
349 | "#endif\n" |
350 | "extern int hook_int_rtx_1 (rtx);\n" |
351 | "#if !HAVE_ATTR_enabled\n" |
352 | "#define get_attr_enabled hook_int_rtx_1\n" |
353 | "#endif\n" |
354 | "#if !HAVE_ATTR_preferred_for_size\n" |
355 | "#define get_attr_preferred_for_size hook_int_rtx_1\n" |
356 | "#endif\n" |
357 | "#if !HAVE_ATTR_preferred_for_speed\n" |
358 | "#define get_attr_preferred_for_speed hook_int_rtx_1\n" |
359 | "#endif\n" ); |
360 | |
361 | /* Output flag masks for use by reorg. |
362 | |
363 | Flags are used to hold branch direction for use by eligible_for_... */ |
364 | printf (format: "\n#define ATTR_FLAG_forward\t0x1\n" ); |
365 | printf (format: "#define ATTR_FLAG_backward\t0x2\n" ); |
366 | |
367 | puts (s: "\n#endif /* GCC_INSN_ATTR_H */" ); |
368 | |
369 | if (ferror (stdout) || fflush (stdout) || fclose (stdout)) |
370 | return FATAL_EXIT_CODE; |
371 | |
372 | return SUCCESS_EXIT_CODE; |
373 | } |
374 | |