]>
Commit | Line | Data |
---|---|---|
96d905e5 | 1 | /* Support routines for the various generation passes. |
7cf0dbf3 | 2 | Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, |
3 | 2010, Free Software Foundation, Inc. | |
c5ddd6b5 | 4 | |
f12b58b3 | 5 | This file is part of GCC. |
c5ddd6b5 | 6 | |
f12b58b3 | 7 | GCC is free software; you can redistribute it and/or modify it |
8 | under the terms of the GNU General Public License as published by | |
8c4c00c1 | 9 | the Free Software Foundation; either version 3, or (at your option) |
c5ddd6b5 | 10 | any later version. |
11 | ||
f12b58b3 | 12 | GCC is distributed in the hope that it will be useful, but WITHOUT |
13 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
14 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
15 | License for more details. | |
c5ddd6b5 | 16 | |
17 | You should have received a copy of the GNU General Public License | |
8c4c00c1 | 18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. */ | |
c5ddd6b5 | 20 | |
805e22b2 | 21 | #include "bconfig.h" |
c5ddd6b5 | 22 | #include "system.h" |
805e22b2 | 23 | #include "coretypes.h" |
24 | #include "tm.h" | |
c5ddd6b5 | 25 | #include "rtl.h" |
96d905e5 | 26 | #include "obstack.h" |
c5ddd6b5 | 27 | #include "errors.h" |
b70bd542 | 28 | #include "hashtab.h" |
960ebfe7 | 29 | #include "read-md.h" |
c5ddd6b5 | 30 | #include "gensupport.h" |
31 | ||
96d905e5 | 32 | |
420f5e4e | 33 | /* In case some macros used by files we include need it, define this here. */ |
34 | int target_flags; | |
35 | ||
b70bd542 | 36 | int insn_elision = 1; |
37 | ||
cbf464bd | 38 | const char *in_fname; |
39 | ||
96128417 | 40 | /* This callback will be invoked whenever an rtl include directive is |
41 | processed. To be used for creation of the dependency file. */ | |
42 | void (*include_callback) (const char *); | |
43 | ||
96d905e5 | 44 | static struct obstack obstack; |
45 | struct obstack *rtl_obstack = &obstack; | |
46 | ||
c5ddd6b5 | 47 | static int sequence_num; |
1df8f1eb | 48 | static int errors; |
49 | ||
50 | static int predicable_default; | |
51 | static const char *predicable_true; | |
52 | static const char *predicable_false; | |
53 | ||
b70bd542 | 54 | static htab_t condition_table; |
55 | ||
2b6e1955 | 56 | static char *base_dir = NULL; |
57 | ||
1df8f1eb | 58 | /* We initially queue all patterns, process the define_insn and |
59 | define_cond_exec patterns, then return them one at a time. */ | |
c5ddd6b5 | 60 | |
1df8f1eb | 61 | struct queue_elem |
62 | { | |
63 | rtx data; | |
f1c96ec2 | 64 | const char *filename; |
1df8f1eb | 65 | int lineno; |
66 | struct queue_elem *next; | |
96f57e36 | 67 | /* In a DEFINE_INSN that came from a DEFINE_INSN_AND_SPLIT, SPLIT |
68 | points to the generated DEFINE_SPLIT. */ | |
69 | struct queue_elem *split; | |
c5ddd6b5 | 70 | }; |
71 | ||
1df8f1eb | 72 | static struct queue_elem *define_attr_queue; |
73 | static struct queue_elem **define_attr_tail = &define_attr_queue; | |
cbf464bd | 74 | static struct queue_elem *define_pred_queue; |
75 | static struct queue_elem **define_pred_tail = &define_pred_queue; | |
1df8f1eb | 76 | static struct queue_elem *define_insn_queue; |
77 | static struct queue_elem **define_insn_tail = &define_insn_queue; | |
78 | static struct queue_elem *define_cond_exec_queue; | |
79 | static struct queue_elem **define_cond_exec_tail = &define_cond_exec_queue; | |
80 | static struct queue_elem *other_queue; | |
81 | static struct queue_elem **other_tail = &other_queue; | |
c5ddd6b5 | 82 | |
96f57e36 | 83 | static struct queue_elem *queue_pattern (rtx, struct queue_elem ***, |
84 | const char *, int); | |
2b6e1955 | 85 | |
86 | /* Current maximum length of directory names in the search path | |
87 | for include files. (Altered as we get more of them.) */ | |
88 | ||
89 | size_t max_include_len; | |
90 | ||
91 | struct file_name_list | |
92 | { | |
93 | struct file_name_list *next; | |
94 | const char *fname; | |
95 | }; | |
96 | ||
6a81282b | 97 | struct file_name_list *first_dir_md_include = 0; /* First dir to search */ |
2b6e1955 | 98 | /* First dir to search for <file> */ |
99 | struct file_name_list *first_bracket_include = 0; | |
6a81282b | 100 | struct file_name_list *last_dir_md_include = 0; /* Last in chain */ |
2b6e1955 | 101 | |
1a97be37 | 102 | static void remove_constraints (rtx); |
103 | static void process_rtx (rtx, int); | |
104 | ||
105 | static int is_predicable (struct queue_elem *); | |
106 | static void identify_predicable_attribute (void); | |
107 | static int n_alternatives (const char *); | |
108 | static void collect_insn_data (rtx, int *, int *); | |
109 | static rtx alter_predicate_for_insn (rtx, int, int, int); | |
110 | static const char *alter_test_for_insn (struct queue_elem *, | |
111 | struct queue_elem *); | |
112 | static char *shift_output_template (char *, const char *, int); | |
113 | static const char *alter_output_for_insn (struct queue_elem *, | |
114 | struct queue_elem *, | |
115 | int, int); | |
116 | static void process_one_cond_exec (struct queue_elem *); | |
117 | static void process_define_cond_exec (void); | |
118 | static void process_include (rtx, int); | |
119 | static char *save_string (const char *, int); | |
cbf464bd | 120 | static void init_predicate_table (void); |
343695df | 121 | static void record_insn_name (int, const char *); |
96d905e5 | 122 | \f |
5cc193e7 | 123 | /* Make a version of gen_rtx_CONST_INT so that GEN_INT can be used in |
124 | the gensupport programs. */ | |
125 | ||
126 | rtx | |
9a03a746 | 127 | gen_rtx_CONST_INT (enum machine_mode ARG_UNUSED (mode), |
1a97be37 | 128 | HOST_WIDE_INT arg) |
5cc193e7 | 129 | { |
130 | rtx rt = rtx_alloc (CONST_INT); | |
131 | ||
132 | XWINT (rt, 0) = arg; | |
133 | return rt; | |
134 | } | |
96d905e5 | 135 | \f |
96f57e36 | 136 | /* Queue PATTERN on LIST_TAIL. Return the address of the new queue |
137 | element. */ | |
1df8f1eb | 138 | |
96f57e36 | 139 | static struct queue_elem * |
1a97be37 | 140 | queue_pattern (rtx pattern, struct queue_elem ***list_tail, |
141 | const char *filename, int lineno) | |
1df8f1eb | 142 | { |
9318f22c | 143 | struct queue_elem *e = XNEW(struct queue_elem); |
1df8f1eb | 144 | e->data = pattern; |
f1c96ec2 | 145 | e->filename = filename; |
1df8f1eb | 146 | e->lineno = lineno; |
147 | e->next = NULL; | |
96f57e36 | 148 | e->split = NULL; |
1df8f1eb | 149 | **list_tail = e; |
150 | *list_tail = &e->next; | |
96f57e36 | 151 | return e; |
1df8f1eb | 152 | } |
153 | ||
c5ddd6b5 | 154 | /* Recursively remove constraints from an rtx. */ |
155 | ||
156 | static void | |
1a97be37 | 157 | remove_constraints (rtx part) |
c5ddd6b5 | 158 | { |
19cb6b50 | 159 | int i, j; |
160 | const char *format_ptr; | |
c5ddd6b5 | 161 | |
162 | if (part == 0) | |
163 | return; | |
164 | ||
165 | if (GET_CODE (part) == MATCH_OPERAND) | |
166 | XSTR (part, 2) = ""; | |
167 | else if (GET_CODE (part) == MATCH_SCRATCH) | |
168 | XSTR (part, 1) = ""; | |
169 | ||
170 | format_ptr = GET_RTX_FORMAT (GET_CODE (part)); | |
171 | ||
172 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) | |
173 | switch (*format_ptr++) | |
174 | { | |
175 | case 'e': | |
176 | case 'u': | |
177 | remove_constraints (XEXP (part, i)); | |
178 | break; | |
179 | case 'E': | |
180 | if (XVEC (part, i) != NULL) | |
181 | for (j = 0; j < XVECLEN (part, i); j++) | |
182 | remove_constraints (XVECEXP (part, i, j)); | |
183 | break; | |
184 | } | |
185 | } | |
186 | ||
1a97be37 | 187 | /* Process an include file assuming that it lives in gcc/config/{target}/ |
3c879f1d | 188 | if the include looks like (include "file"). */ |
c93cef3a | 189 | |
190 | static void | |
1a97be37 | 191 | process_include (rtx desc, int lineno) |
2b6e1955 | 192 | { |
193 | const char *filename = XSTR (desc, 0); | |
c93cef3a | 194 | const char *old_filename; |
195 | int old_lineno; | |
196 | char *pathname; | |
2b6e1955 | 197 | FILE *input_file; |
2b6e1955 | 198 | |
c93cef3a | 199 | /* If specified file name is absolute, skip the include stack. */ |
a5c088d4 | 200 | if (! IS_ABSOLUTE_PATH (filename)) |
2b6e1955 | 201 | { |
c93cef3a | 202 | struct file_name_list *stackp; |
203 | ||
204 | /* Search directory path, trying to open the file. */ | |
205 | for (stackp = first_dir_md_include; stackp; stackp = stackp->next) | |
2b6e1955 | 206 | { |
c93cef3a | 207 | static const char sep[2] = { DIR_SEPARATOR, '\0' }; |
208 | ||
209 | pathname = concat (stackp->fname, sep, filename, NULL); | |
210 | input_file = fopen (pathname, "r"); | |
1a97be37 | 211 | if (input_file != NULL) |
c93cef3a | 212 | goto success; |
213 | free (pathname); | |
2b6e1955 | 214 | } |
215 | } | |
2b6e1955 | 216 | |
c93cef3a | 217 | if (base_dir) |
218 | pathname = concat (base_dir, filename, NULL); | |
219 | else | |
220 | pathname = xstrdup (filename); | |
221 | input_file = fopen (pathname, "r"); | |
222 | if (input_file == NULL) | |
223 | { | |
224 | free (pathname); | |
225 | message_with_line (lineno, "include file `%s' not found", filename); | |
226 | errors = 1; | |
227 | return; | |
228 | } | |
229 | success: | |
2b6e1955 | 230 | |
c93cef3a | 231 | /* Save old cursor; setup new for the new file. Note that "lineno" the |
232 | argument to this function is the beginning of the include statement, | |
233 | while read_rtx_lineno has already been advanced. */ | |
234 | old_filename = read_rtx_filename; | |
235 | old_lineno = read_rtx_lineno; | |
236 | read_rtx_filename = pathname; | |
237 | read_rtx_lineno = 1; | |
2b6e1955 | 238 | |
96128417 | 239 | if (include_callback) |
240 | include_callback (pathname); | |
241 | ||
c93cef3a | 242 | /* Read the entire file. */ |
fea520eb | 243 | while (read_rtx (input_file, &desc, &lineno)) |
244 | process_rtx (desc, lineno); | |
2b6e1955 | 245 | |
f1c96ec2 | 246 | /* Do not free pathname. It is attached to the various rtx queue |
247 | elements. */ | |
248 | ||
c93cef3a | 249 | read_rtx_filename = old_filename; |
250 | read_rtx_lineno = old_lineno; | |
2b6e1955 | 251 | |
c93cef3a | 252 | fclose (input_file); |
2b6e1955 | 253 | } |
254 | ||
40e55fbb | 255 | /* Process a top level rtx in some way, queuing as appropriate. */ |
c5ddd6b5 | 256 | |
257 | static void | |
1a97be37 | 258 | process_rtx (rtx desc, int lineno) |
1df8f1eb | 259 | { |
260 | switch (GET_CODE (desc)) | |
261 | { | |
262 | case DEFINE_INSN: | |
f1c96ec2 | 263 | queue_pattern (desc, &define_insn_tail, read_rtx_filename, lineno); |
1df8f1eb | 264 | break; |
265 | ||
266 | case DEFINE_COND_EXEC: | |
f1c96ec2 | 267 | queue_pattern (desc, &define_cond_exec_tail, read_rtx_filename, lineno); |
1df8f1eb | 268 | break; |
269 | ||
270 | case DEFINE_ATTR: | |
f1c96ec2 | 271 | queue_pattern (desc, &define_attr_tail, read_rtx_filename, lineno); |
1df8f1eb | 272 | break; |
273 | ||
cbf464bd | 274 | case DEFINE_PREDICATE: |
275 | case DEFINE_SPECIAL_PREDICATE: | |
026d3868 | 276 | case DEFINE_CONSTRAINT: |
277 | case DEFINE_REGISTER_CONSTRAINT: | |
278 | case DEFINE_MEMORY_CONSTRAINT: | |
279 | case DEFINE_ADDRESS_CONSTRAINT: | |
cbf464bd | 280 | queue_pattern (desc, &define_pred_tail, read_rtx_filename, lineno); |
281 | break; | |
282 | ||
2b6e1955 | 283 | case INCLUDE: |
c93cef3a | 284 | process_include (desc, lineno); |
2b6e1955 | 285 | break; |
286 | ||
1df8f1eb | 287 | case DEFINE_INSN_AND_SPLIT: |
288 | { | |
289 | const char *split_cond; | |
5dd13b1d | 290 | rtx split; |
291 | rtvec attr; | |
6ef7f25d | 292 | int i; |
96f57e36 | 293 | struct queue_elem *insn_elem; |
294 | struct queue_elem *split_elem; | |
1df8f1eb | 295 | |
aa40f561 | 296 | /* Create a split with values from the insn_and_split. */ |
1df8f1eb | 297 | split = rtx_alloc (DEFINE_SPLIT); |
6ef7f25d | 298 | |
299 | i = XVECLEN (desc, 1); | |
2508fdc3 | 300 | XVEC (split, 0) = rtvec_alloc (i); |
6ef7f25d | 301 | while (--i >= 0) |
302 | { | |
303 | XVECEXP (split, 0, i) = copy_rtx (XVECEXP (desc, 1, i)); | |
304 | remove_constraints (XVECEXP (split, 0, i)); | |
305 | } | |
1df8f1eb | 306 | |
307 | /* If the split condition starts with "&&", append it to the | |
308 | insn condition to create the new split condition. */ | |
309 | split_cond = XSTR (desc, 4); | |
310 | if (split_cond[0] == '&' && split_cond[1] == '&') | |
9e959634 | 311 | { |
312 | copy_rtx_ptr_loc (split_cond + 2, split_cond); | |
313 | split_cond = join_c_conditions (XSTR (desc, 2), split_cond + 2); | |
314 | } | |
1df8f1eb | 315 | XSTR (split, 1) = split_cond; |
316 | XVEC (split, 2) = XVEC (desc, 5); | |
317 | XSTR (split, 3) = XSTR (desc, 6); | |
318 | ||
319 | /* Fix up the DEFINE_INSN. */ | |
5a9f7b1b | 320 | attr = XVEC (desc, 7); |
1df8f1eb | 321 | PUT_CODE (desc, DEFINE_INSN); |
5a9f7b1b | 322 | XVEC (desc, 4) = attr; |
1df8f1eb | 323 | |
324 | /* Queue them. */ | |
96f57e36 | 325 | insn_elem |
48e1416a | 326 | = queue_pattern (desc, &define_insn_tail, read_rtx_filename, |
96f57e36 | 327 | lineno); |
328 | split_elem | |
329 | = queue_pattern (split, &other_tail, read_rtx_filename, lineno); | |
330 | insn_elem->split = split_elem; | |
1df8f1eb | 331 | break; |
332 | } | |
333 | ||
334 | default: | |
f1c96ec2 | 335 | queue_pattern (desc, &other_tail, read_rtx_filename, lineno); |
1df8f1eb | 336 | break; |
c5ddd6b5 | 337 | } |
338 | } | |
96d905e5 | 339 | \f |
1df8f1eb | 340 | /* Return true if attribute PREDICABLE is true for ELEM, which holds |
341 | a DEFINE_INSN. */ | |
342 | ||
343 | static int | |
1a97be37 | 344 | is_predicable (struct queue_elem *elem) |
1df8f1eb | 345 | { |
346 | rtvec vec = XVEC (elem->data, 4); | |
347 | const char *value; | |
348 | int i; | |
349 | ||
350 | if (! vec) | |
351 | return predicable_default; | |
352 | ||
353 | for (i = GET_NUM_ELEM (vec) - 1; i >= 0; --i) | |
354 | { | |
355 | rtx sub = RTVEC_ELT (vec, i); | |
356 | switch (GET_CODE (sub)) | |
357 | { | |
358 | case SET_ATTR: | |
359 | if (strcmp (XSTR (sub, 0), "predicable") == 0) | |
360 | { | |
361 | value = XSTR (sub, 1); | |
362 | goto found; | |
363 | } | |
364 | break; | |
365 | ||
366 | case SET_ATTR_ALTERNATIVE: | |
367 | if (strcmp (XSTR (sub, 0), "predicable") == 0) | |
368 | { | |
369 | message_with_line (elem->lineno, | |
370 | "multiple alternatives for `predicable'"); | |
371 | errors = 1; | |
372 | return 0; | |
373 | } | |
374 | break; | |
375 | ||
376 | case SET: | |
377 | if (GET_CODE (SET_DEST (sub)) != ATTR | |
378 | || strcmp (XSTR (SET_DEST (sub), 0), "predicable") != 0) | |
379 | break; | |
380 | sub = SET_SRC (sub); | |
381 | if (GET_CODE (sub) == CONST_STRING) | |
382 | { | |
383 | value = XSTR (sub, 0); | |
384 | goto found; | |
385 | } | |
386 | ||
387 | /* ??? It would be possible to handle this if we really tried. | |
388 | It's not easy though, and I'm not going to bother until it | |
389 | really proves necessary. */ | |
390 | message_with_line (elem->lineno, | |
391 | "non-constant value for `predicable'"); | |
392 | errors = 1; | |
393 | return 0; | |
394 | ||
395 | default: | |
e0a4c0c2 | 396 | gcc_unreachable (); |
1df8f1eb | 397 | } |
398 | } | |
399 | ||
400 | return predicable_default; | |
401 | ||
402 | found: | |
403 | /* Verify that predicability does not vary on the alternative. */ | |
404 | /* ??? It should be possible to handle this by simply eliminating | |
405 | the non-predicable alternatives from the insn. FRV would like | |
406 | to do this. Delay this until we've got the basics solid. */ | |
407 | if (strchr (value, ',') != NULL) | |
408 | { | |
409 | message_with_line (elem->lineno, | |
410 | "multiple alternatives for `predicable'"); | |
411 | errors = 1; | |
412 | return 0; | |
413 | } | |
414 | ||
415 | /* Find out which value we're looking at. */ | |
416 | if (strcmp (value, predicable_true) == 0) | |
417 | return 1; | |
418 | if (strcmp (value, predicable_false) == 0) | |
419 | return 0; | |
420 | ||
421 | message_with_line (elem->lineno, | |
cb8bacb6 | 422 | "unknown value `%s' for `predicable' attribute", |
1df8f1eb | 423 | value); |
424 | errors = 1; | |
425 | return 0; | |
426 | } | |
427 | ||
428 | /* Examine the attribute "predicable"; discover its boolean values | |
429 | and its default. */ | |
430 | ||
431 | static void | |
1a97be37 | 432 | identify_predicable_attribute (void) |
1df8f1eb | 433 | { |
434 | struct queue_elem *elem; | |
9c811526 | 435 | char *p_true, *p_false; |
1df8f1eb | 436 | const char *value; |
1df8f1eb | 437 | |
438 | /* Look for the DEFINE_ATTR for `predicable', which must exist. */ | |
439 | for (elem = define_attr_queue; elem ; elem = elem->next) | |
440 | if (strcmp (XSTR (elem->data, 0), "predicable") == 0) | |
441 | goto found; | |
442 | ||
443 | message_with_line (define_cond_exec_queue->lineno, | |
cb8bacb6 | 444 | "attribute `predicable' not defined"); |
1df8f1eb | 445 | errors = 1; |
446 | return; | |
447 | ||
448 | found: | |
449 | value = XSTR (elem->data, 1); | |
9591cb7b | 450 | p_false = xstrdup (value); |
9c811526 | 451 | p_true = strchr (p_false, ','); |
452 | if (p_true == NULL || strchr (++p_true, ',') != NULL) | |
1df8f1eb | 453 | { |
454 | message_with_line (elem->lineno, | |
cb8bacb6 | 455 | "attribute `predicable' is not a boolean"); |
1df8f1eb | 456 | errors = 1; |
6acc9746 | 457 | if (p_false) |
458 | free (p_false); | |
1df8f1eb | 459 | return; |
460 | } | |
9c811526 | 461 | p_true[-1] = '\0'; |
1df8f1eb | 462 | |
9c811526 | 463 | predicable_true = p_true; |
464 | predicable_false = p_false; | |
1df8f1eb | 465 | |
466 | switch (GET_CODE (XEXP (elem->data, 2))) | |
467 | { | |
468 | case CONST_STRING: | |
469 | value = XSTR (XEXP (elem->data, 2), 0); | |
470 | break; | |
471 | ||
472 | case CONST: | |
473 | message_with_line (elem->lineno, | |
cb8bacb6 | 474 | "attribute `predicable' cannot be const"); |
1df8f1eb | 475 | errors = 1; |
6acc9746 | 476 | if (p_false) |
477 | free (p_false); | |
1df8f1eb | 478 | return; |
479 | ||
480 | default: | |
481 | message_with_line (elem->lineno, | |
cb8bacb6 | 482 | "attribute `predicable' must have a constant default"); |
1df8f1eb | 483 | errors = 1; |
6acc9746 | 484 | if (p_false) |
485 | free (p_false); | |
1df8f1eb | 486 | return; |
487 | } | |
488 | ||
9c811526 | 489 | if (strcmp (value, p_true) == 0) |
1df8f1eb | 490 | predicable_default = 1; |
9c811526 | 491 | else if (strcmp (value, p_false) == 0) |
1df8f1eb | 492 | predicable_default = 0; |
493 | else | |
494 | { | |
495 | message_with_line (elem->lineno, | |
cb8bacb6 | 496 | "unknown value `%s' for `predicable' attribute", |
1df8f1eb | 497 | value); |
498 | errors = 1; | |
79bd7049 | 499 | if (p_false) |
500 | free (p_false); | |
1df8f1eb | 501 | } |
502 | } | |
503 | ||
504 | /* Return the number of alternatives in constraint S. */ | |
505 | ||
506 | static int | |
1a97be37 | 507 | n_alternatives (const char *s) |
1df8f1eb | 508 | { |
509 | int n = 1; | |
510 | ||
511 | if (s) | |
512 | while (*s) | |
513 | n += (*s++ == ','); | |
514 | ||
515 | return n; | |
516 | } | |
517 | ||
518 | /* Determine how many alternatives there are in INSN, and how many | |
519 | operands. */ | |
520 | ||
521 | static void | |
1a97be37 | 522 | collect_insn_data (rtx pattern, int *palt, int *pmax) |
1df8f1eb | 523 | { |
524 | const char *fmt; | |
525 | enum rtx_code code; | |
526 | int i, j, len; | |
527 | ||
528 | code = GET_CODE (pattern); | |
529 | switch (code) | |
530 | { | |
531 | case MATCH_OPERAND: | |
f316cb53 | 532 | i = n_alternatives (XSTR (pattern, 2)); |
533 | *palt = (i > *palt ? i : *palt); | |
d632b59a | 534 | /* Fall through. */ |
1df8f1eb | 535 | |
536 | case MATCH_OPERATOR: | |
537 | case MATCH_SCRATCH: | |
538 | case MATCH_PARALLEL: | |
1df8f1eb | 539 | i = XINT (pattern, 0); |
540 | if (i > *pmax) | |
541 | *pmax = i; | |
542 | break; | |
543 | ||
544 | default: | |
545 | break; | |
546 | } | |
547 | ||
548 | fmt = GET_RTX_FORMAT (code); | |
549 | len = GET_RTX_LENGTH (code); | |
550 | for (i = 0; i < len; i++) | |
551 | { | |
552 | switch (fmt[i]) | |
553 | { | |
554 | case 'e': case 'u': | |
555 | collect_insn_data (XEXP (pattern, i), palt, pmax); | |
556 | break; | |
557 | ||
558 | case 'V': | |
559 | if (XVEC (pattern, i) == NULL) | |
560 | break; | |
d632b59a | 561 | /* Fall through. */ |
1df8f1eb | 562 | case 'E': |
563 | for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) | |
564 | collect_insn_data (XVECEXP (pattern, i, j), palt, pmax); | |
565 | break; | |
566 | ||
9abd2cd7 | 567 | case 'i': case 'w': case '0': case 's': case 'S': case 'T': |
1df8f1eb | 568 | break; |
569 | ||
570 | default: | |
e0a4c0c2 | 571 | gcc_unreachable (); |
1df8f1eb | 572 | } |
573 | } | |
574 | } | |
575 | ||
576 | static rtx | |
1a97be37 | 577 | alter_predicate_for_insn (rtx pattern, int alt, int max_op, int lineno) |
1df8f1eb | 578 | { |
579 | const char *fmt; | |
580 | enum rtx_code code; | |
581 | int i, j, len; | |
582 | ||
583 | code = GET_CODE (pattern); | |
584 | switch (code) | |
585 | { | |
586 | case MATCH_OPERAND: | |
587 | { | |
588 | const char *c = XSTR (pattern, 2); | |
589 | ||
590 | if (n_alternatives (c) != 1) | |
591 | { | |
592 | message_with_line (lineno, | |
cb8bacb6 | 593 | "too many alternatives for operand %d", |
1df8f1eb | 594 | XINT (pattern, 0)); |
595 | errors = 1; | |
596 | return NULL; | |
597 | } | |
598 | ||
599 | /* Replicate C as needed to fill out ALT alternatives. */ | |
600 | if (c && *c && alt > 1) | |
601 | { | |
602 | size_t c_len = strlen (c); | |
603 | size_t len = alt * (c_len + 1); | |
9318f22c | 604 | char *new_c = XNEWVEC(char, len); |
1df8f1eb | 605 | |
606 | memcpy (new_c, c, c_len); | |
607 | for (i = 1; i < alt; ++i) | |
608 | { | |
609 | new_c[i * (c_len + 1) - 1] = ','; | |
610 | memcpy (&new_c[i * (c_len + 1)], c, c_len); | |
611 | } | |
612 | new_c[len - 1] = '\0'; | |
613 | XSTR (pattern, 2) = new_c; | |
614 | } | |
615 | } | |
d632b59a | 616 | /* Fall through. */ |
1df8f1eb | 617 | |
618 | case MATCH_OPERATOR: | |
619 | case MATCH_SCRATCH: | |
620 | case MATCH_PARALLEL: | |
1df8f1eb | 621 | XINT (pattern, 0) += max_op; |
622 | break; | |
623 | ||
624 | default: | |
625 | break; | |
626 | } | |
627 | ||
628 | fmt = GET_RTX_FORMAT (code); | |
629 | len = GET_RTX_LENGTH (code); | |
630 | for (i = 0; i < len; i++) | |
631 | { | |
632 | rtx r; | |
633 | ||
634 | switch (fmt[i]) | |
635 | { | |
636 | case 'e': case 'u': | |
637 | r = alter_predicate_for_insn (XEXP (pattern, i), alt, | |
638 | max_op, lineno); | |
639 | if (r == NULL) | |
640 | return r; | |
641 | break; | |
642 | ||
643 | case 'E': | |
644 | for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) | |
645 | { | |
646 | r = alter_predicate_for_insn (XVECEXP (pattern, i, j), | |
647 | alt, max_op, lineno); | |
648 | if (r == NULL) | |
649 | return r; | |
650 | } | |
651 | break; | |
652 | ||
653 | case 'i': case 'w': case '0': case 's': | |
654 | break; | |
655 | ||
656 | default: | |
e0a4c0c2 | 657 | gcc_unreachable (); |
1df8f1eb | 658 | } |
659 | } | |
660 | ||
661 | return pattern; | |
662 | } | |
663 | ||
664 | static const char * | |
1a97be37 | 665 | alter_test_for_insn (struct queue_elem *ce_elem, |
666 | struct queue_elem *insn_elem) | |
1df8f1eb | 667 | { |
9e959634 | 668 | return join_c_conditions (XSTR (ce_elem->data, 1), |
669 | XSTR (insn_elem->data, 2)); | |
1df8f1eb | 670 | } |
671 | ||
e85905e5 | 672 | /* Adjust all of the operand numbers in SRC to match the shift they'll |
1df8f1eb | 673 | get from an operand displacement of DISP. Return a pointer after the |
674 | adjusted string. */ | |
675 | ||
676 | static char * | |
e85905e5 | 677 | shift_output_template (char *dest, const char *src, int disp) |
1df8f1eb | 678 | { |
e85905e5 | 679 | while (*src) |
1df8f1eb | 680 | { |
e85905e5 | 681 | char c = *src++; |
1ae4d088 | 682 | *dest++ = c; |
1df8f1eb | 683 | if (c == '%') |
684 | { | |
e85905e5 | 685 | c = *src++; |
1df8f1eb | 686 | if (ISDIGIT ((unsigned char) c)) |
687 | c += disp; | |
66a33570 | 688 | else if (ISALPHA (c)) |
1df8f1eb | 689 | { |
1ae4d088 | 690 | *dest++ = c; |
e85905e5 | 691 | c = *src++ + disp; |
1df8f1eb | 692 | } |
1ae4d088 | 693 | *dest++ = c; |
1df8f1eb | 694 | } |
695 | } | |
696 | ||
1ae4d088 | 697 | return dest; |
1df8f1eb | 698 | } |
699 | ||
700 | static const char * | |
1a97be37 | 701 | alter_output_for_insn (struct queue_elem *ce_elem, |
702 | struct queue_elem *insn_elem, | |
703 | int alt, int max_op) | |
1df8f1eb | 704 | { |
705 | const char *ce_out, *insn_out; | |
1ae4d088 | 706 | char *result, *p; |
1df8f1eb | 707 | size_t len, ce_len, insn_len; |
708 | ||
709 | /* ??? Could coordinate with genoutput to not duplicate code here. */ | |
710 | ||
711 | ce_out = XSTR (ce_elem->data, 2); | |
4a9e3377 | 712 | insn_out = XTMPL (insn_elem->data, 3); |
1df8f1eb | 713 | if (!ce_out || *ce_out == '\0') |
714 | return insn_out; | |
715 | ||
716 | ce_len = strlen (ce_out); | |
717 | insn_len = strlen (insn_out); | |
718 | ||
719 | if (*insn_out == '*') | |
720 | /* You must take care of the predicate yourself. */ | |
721 | return insn_out; | |
722 | ||
723 | if (*insn_out == '@') | |
724 | { | |
725 | len = (ce_len + 1) * alt + insn_len + 1; | |
1ae4d088 | 726 | p = result = XNEWVEC(char, len); |
1df8f1eb | 727 | |
728 | do | |
729 | { | |
730 | do | |
731 | *p++ = *insn_out++; | |
732 | while (ISSPACE ((unsigned char) *insn_out)); | |
733 | ||
734 | if (*insn_out != '#') | |
735 | { | |
736 | p = shift_output_template (p, ce_out, max_op); | |
737 | *p++ = ' '; | |
738 | } | |
739 | ||
740 | do | |
741 | *p++ = *insn_out++; | |
742 | while (*insn_out && *insn_out != '\n'); | |
743 | } | |
744 | while (*insn_out); | |
745 | *p = '\0'; | |
746 | } | |
747 | else | |
748 | { | |
749 | len = ce_len + 1 + insn_len + 1; | |
1ae4d088 | 750 | result = XNEWVEC (char, len); |
1df8f1eb | 751 | |
1ae4d088 | 752 | p = shift_output_template (result, ce_out, max_op); |
1df8f1eb | 753 | *p++ = ' '; |
754 | memcpy (p, insn_out, insn_len + 1); | |
755 | } | |
756 | ||
1ae4d088 | 757 | return result; |
1df8f1eb | 758 | } |
759 | ||
760 | /* Replicate insns as appropriate for the given DEFINE_COND_EXEC. */ | |
761 | ||
762 | static void | |
1a97be37 | 763 | process_one_cond_exec (struct queue_elem *ce_elem) |
1df8f1eb | 764 | { |
765 | struct queue_elem *insn_elem; | |
766 | for (insn_elem = define_insn_queue; insn_elem ; insn_elem = insn_elem->next) | |
767 | { | |
768 | int alternatives, max_operand; | |
96f57e36 | 769 | rtx pred, insn, pattern, split; |
5bc0532c | 770 | char *new_name; |
96f57e36 | 771 | int i; |
1df8f1eb | 772 | |
773 | if (! is_predicable (insn_elem)) | |
774 | continue; | |
775 | ||
776 | alternatives = 1; | |
777 | max_operand = -1; | |
778 | collect_insn_data (insn_elem->data, &alternatives, &max_operand); | |
779 | max_operand += 1; | |
780 | ||
781 | if (XVECLEN (ce_elem->data, 0) != 1) | |
782 | { | |
783 | message_with_line (ce_elem->lineno, | |
784 | "too many patterns in predicate"); | |
785 | errors = 1; | |
786 | return; | |
787 | } | |
788 | ||
789 | pred = copy_rtx (XVECEXP (ce_elem->data, 0, 0)); | |
790 | pred = alter_predicate_for_insn (pred, alternatives, max_operand, | |
791 | ce_elem->lineno); | |
792 | if (pred == NULL) | |
793 | return; | |
794 | ||
795 | /* Construct a new pattern for the new insn. */ | |
796 | insn = copy_rtx (insn_elem->data); | |
5bc0532c | 797 | new_name = XNEWVAR (char, strlen XSTR (insn_elem->data, 0) + 4); |
798 | sprintf (new_name, "*p %s", XSTR (insn_elem->data, 0)); | |
799 | XSTR (insn, 0) = new_name; | |
1df8f1eb | 800 | pattern = rtx_alloc (COND_EXEC); |
801 | XEXP (pattern, 0) = pred; | |
802 | if (XVECLEN (insn, 1) == 1) | |
803 | { | |
804 | XEXP (pattern, 1) = XVECEXP (insn, 1, 0); | |
805 | XVECEXP (insn, 1, 0) = pattern; | |
806 | PUT_NUM_ELEM (XVEC (insn, 1), 1); | |
807 | } | |
808 | else | |
809 | { | |
810 | XEXP (pattern, 1) = rtx_alloc (PARALLEL); | |
811 | XVEC (XEXP (pattern, 1), 0) = XVEC (insn, 1); | |
812 | XVEC (insn, 1) = rtvec_alloc (1); | |
813 | XVECEXP (insn, 1, 0) = pattern; | |
814 | } | |
815 | ||
816 | XSTR (insn, 2) = alter_test_for_insn (ce_elem, insn_elem); | |
4a9e3377 | 817 | XTMPL (insn, 3) = alter_output_for_insn (ce_elem, insn_elem, |
1df8f1eb | 818 | alternatives, max_operand); |
819 | ||
820 | /* ??? Set `predicable' to false. Not crucial since it's really | |
821 | only used here, and we won't reprocess this new pattern. */ | |
822 | ||
823 | /* Put the new pattern on the `other' list so that it | |
824 | (a) is not reprocessed by other define_cond_exec patterns | |
825 | (b) appears after all normal define_insn patterns. | |
826 | ||
827 | ??? B is debatable. If one has normal insns that match | |
828 | cond_exec patterns, they will be preferred over these | |
829 | generated patterns. Whether this matters in practice, or if | |
830 | it's a good thing, or whether we should thread these new | |
831 | patterns into the define_insn chain just after their generator | |
832 | is something we'll have to experiment with. */ | |
833 | ||
f1c96ec2 | 834 | queue_pattern (insn, &other_tail, insn_elem->filename, |
835 | insn_elem->lineno); | |
96f57e36 | 836 | |
837 | if (!insn_elem->split) | |
838 | continue; | |
839 | ||
840 | /* If the original insn came from a define_insn_and_split, | |
0bed3869 | 841 | generate a new split to handle the predicated insn. */ |
96f57e36 | 842 | split = copy_rtx (insn_elem->split->data); |
843 | /* Predicate the pattern matched by the split. */ | |
844 | pattern = rtx_alloc (COND_EXEC); | |
845 | XEXP (pattern, 0) = pred; | |
846 | if (XVECLEN (split, 0) == 1) | |
847 | { | |
848 | XEXP (pattern, 1) = XVECEXP (split, 0, 0); | |
849 | XVECEXP (split, 0, 0) = pattern; | |
850 | PUT_NUM_ELEM (XVEC (split, 0), 1); | |
851 | } | |
852 | else | |
853 | { | |
854 | XEXP (pattern, 1) = rtx_alloc (PARALLEL); | |
855 | XVEC (XEXP (pattern, 1), 0) = XVEC (split, 0); | |
856 | XVEC (split, 0) = rtvec_alloc (1); | |
857 | XVECEXP (split, 0, 0) = pattern; | |
858 | } | |
859 | /* Predicate all of the insns generated by the split. */ | |
860 | for (i = 0; i < XVECLEN (split, 2); i++) | |
861 | { | |
862 | pattern = rtx_alloc (COND_EXEC); | |
863 | XEXP (pattern, 0) = pred; | |
864 | XEXP (pattern, 1) = XVECEXP (split, 2, i); | |
865 | XVECEXP (split, 2, i) = pattern; | |
866 | } | |
867 | /* Add the new split to the queue. */ | |
48e1416a | 868 | queue_pattern (split, &other_tail, read_rtx_filename, |
96f57e36 | 869 | insn_elem->split->lineno); |
1df8f1eb | 870 | } |
871 | } | |
872 | ||
873 | /* If we have any DEFINE_COND_EXEC patterns, expand the DEFINE_INSN | |
874 | patterns appropriately. */ | |
875 | ||
876 | static void | |
1a97be37 | 877 | process_define_cond_exec (void) |
1df8f1eb | 878 | { |
879 | struct queue_elem *elem; | |
880 | ||
881 | identify_predicable_attribute (); | |
882 | if (errors) | |
883 | return; | |
884 | ||
885 | for (elem = define_cond_exec_queue; elem ; elem = elem->next) | |
886 | process_one_cond_exec (elem); | |
887 | } | |
2b6e1955 | 888 | |
889 | static char * | |
1a97be37 | 890 | save_string (const char *s, int len) |
2b6e1955 | 891 | { |
9318f22c | 892 | char *result = XNEWVEC (char, len + 1); |
2b6e1955 | 893 | |
894 | memcpy (result, s, len); | |
895 | result[len] = 0; | |
896 | return result; | |
897 | } | |
898 | ||
899 | \f | |
900 | /* The entry point for initializing the reader. */ | |
901 | ||
902 | int | |
ba08da2c | 903 | init_md_reader_args_cb (int argc, char **argv, bool (*parse_opt)(const char *)) |
2b6e1955 | 904 | { |
ba08da2c | 905 | FILE *input_file; |
af908c02 | 906 | int c, i, lineno; |
ba08da2c | 907 | char *lastsl; |
fea520eb | 908 | rtx desc; |
af908c02 | 909 | bool no_more_options; |
910 | bool already_read_stdin; | |
2b6e1955 | 911 | |
4367c81f | 912 | /* Unlock the stdio streams. */ |
9c8f076b | 913 | unlock_std_streams (); |
4367c81f | 914 | |
af908c02 | 915 | /* First we loop over all the options. */ |
2b6e1955 | 916 | for (i = 1; i < argc; i++) |
917 | { | |
918 | if (argv[i][0] != '-') | |
af908c02 | 919 | continue; |
48e1416a | 920 | |
af908c02 | 921 | c = argv[i][1]; |
922 | switch (c) | |
2b6e1955 | 923 | { |
af908c02 | 924 | case 'I': /* Add directory to path for includes. */ |
925 | { | |
926 | struct file_name_list *dirtmp; | |
927 | ||
928 | dirtmp = XNEW (struct file_name_list); | |
929 | dirtmp->next = 0; /* New one goes on the end */ | |
930 | if (first_dir_md_include == 0) | |
931 | first_dir_md_include = dirtmp; | |
932 | else | |
933 | last_dir_md_include->next = dirtmp; | |
934 | last_dir_md_include = dirtmp; /* Tail follows the last one */ | |
935 | if (argv[i][1] == 'I' && argv[i][2] != 0) | |
936 | dirtmp->fname = argv[i] + 2; | |
937 | else if (i + 1 == argc) | |
938 | fatal ("directory name missing after -I option"); | |
939 | else | |
940 | dirtmp->fname = argv[++i]; | |
941 | if (strlen (dirtmp->fname) > max_include_len) | |
942 | max_include_len = strlen (dirtmp->fname); | |
943 | } | |
944 | break; | |
ba08da2c | 945 | |
af908c02 | 946 | case '\0': |
947 | /* An argument consisting of exactly one dash is a request to | |
948 | read stdin. This will be handled in the second loop. */ | |
949 | continue; | |
c5ddd6b5 | 950 | |
af908c02 | 951 | case '-': |
952 | /* An argument consisting of just two dashes causes option | |
953 | parsing to cease. */ | |
954 | if (argv[i][2] == '\0') | |
955 | goto stop_parsing_options; | |
2b6e1955 | 956 | |
af908c02 | 957 | default: |
958 | /* The program may have provided a callback so it can | |
959 | accept its own options. */ | |
960 | if (parse_opt && parse_opt (argv[i])) | |
961 | break; | |
1df8f1eb | 962 | |
af908c02 | 963 | fatal ("invalid option `%s'", argv[i]); |
964 | } | |
c5ddd6b5 | 965 | } |
966 | ||
af908c02 | 967 | stop_parsing_options: |
b70bd542 | 968 | |
af908c02 | 969 | /* Prepare to read input. */ |
970 | condition_table = htab_create (500, hash_c_test, cmp_c_test, NULL); | |
cbf464bd | 971 | init_predicate_table (); |
96d905e5 | 972 | obstack_init (rtl_obstack); |
1df8f1eb | 973 | errors = 0; |
c5ddd6b5 | 974 | sequence_num = 0; |
af908c02 | 975 | no_more_options = false; |
976 | already_read_stdin = false; | |
c5ddd6b5 | 977 | |
af908c02 | 978 | |
979 | /* Now loop over all input files. */ | |
980 | for (i = 1; i < argc; i++) | |
981 | { | |
982 | if (argv[i][0] == '-') | |
983 | { | |
984 | if (argv[i][1] == '\0') | |
985 | { | |
986 | /* Read stdin. */ | |
987 | if (already_read_stdin) | |
988 | fatal ("cannot read standard input twice"); | |
48e1416a | 989 | |
af908c02 | 990 | base_dir = NULL; |
991 | read_rtx_filename = in_fname = "<stdin>"; | |
992 | read_rtx_lineno = 1; | |
993 | input_file = stdin; | |
994 | already_read_stdin = true; | |
995 | ||
996 | while (read_rtx (input_file, &desc, &lineno)) | |
997 | process_rtx (desc, lineno); | |
998 | fclose (input_file); | |
999 | continue; | |
1000 | } | |
1001 | else if (argv[i][1] == '-' && argv[i][2] == '\0') | |
1002 | { | |
1003 | /* No further arguments are to be treated as options. */ | |
1004 | no_more_options = true; | |
1005 | continue; | |
1006 | } | |
1007 | else if (!no_more_options) | |
1008 | continue; | |
1009 | } | |
1010 | ||
1011 | /* If we get here we are looking at a non-option argument, i.e. | |
1012 | a file to be processed. */ | |
1013 | ||
1014 | in_fname = argv[i]; | |
1015 | lastsl = strrchr (in_fname, '/'); | |
1016 | if (lastsl != NULL) | |
1017 | base_dir = save_string (in_fname, lastsl - in_fname + 1 ); | |
1018 | else | |
1019 | base_dir = NULL; | |
1020 | ||
1021 | read_rtx_filename = in_fname; | |
1022 | read_rtx_lineno = 1; | |
1023 | input_file = fopen (in_fname, "r"); | |
1024 | if (input_file == 0) | |
1025 | { | |
1026 | perror (in_fname); | |
1027 | return FATAL_EXIT_CODE; | |
1028 | } | |
1029 | ||
1030 | while (read_rtx (input_file, &desc, &lineno)) | |
1031 | process_rtx (desc, lineno); | |
1032 | fclose (input_file); | |
1033 | } | |
1034 | ||
1035 | /* If we get to this point without having seen any files to process, | |
1036 | read standard input now. */ | |
1037 | if (!in_fname) | |
1038 | { | |
1039 | base_dir = NULL; | |
1040 | read_rtx_filename = in_fname = "<stdin>"; | |
1041 | read_rtx_lineno = 1; | |
1042 | input_file = stdin; | |
1043 | ||
1044 | while (read_rtx (input_file, &desc, &lineno)) | |
1045 | process_rtx (desc, lineno); | |
1046 | fclose (input_file); | |
1047 | } | |
1df8f1eb | 1048 | |
1049 | /* Process define_cond_exec patterns. */ | |
1050 | if (define_cond_exec_queue != NULL) | |
1051 | process_define_cond_exec (); | |
1052 | ||
1053 | return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE; | |
1054 | } | |
1055 | ||
ba08da2c | 1056 | /* Programs that don't have their own options can use this entry point |
1057 | instead. */ | |
1058 | int | |
1059 | init_md_reader_args (int argc, char **argv) | |
1060 | { | |
1061 | return init_md_reader_args_cb (argc, argv, 0); | |
1062 | } | |
1063 | \f | |
1df8f1eb | 1064 | /* The entry point for reading a single rtx from an md file. */ |
1065 | ||
1066 | rtx | |
1a97be37 | 1067 | read_md_rtx (int *lineno, int *seqnr) |
1df8f1eb | 1068 | { |
1069 | struct queue_elem **queue, *elem; | |
1070 | rtx desc; | |
1071 | ||
b70bd542 | 1072 | discard: |
1073 | ||
1df8f1eb | 1074 | /* Read all patterns from a given queue before moving on to the next. */ |
1075 | if (define_attr_queue != NULL) | |
1076 | queue = &define_attr_queue; | |
cbf464bd | 1077 | else if (define_pred_queue != NULL) |
1078 | queue = &define_pred_queue; | |
1df8f1eb | 1079 | else if (define_insn_queue != NULL) |
1080 | queue = &define_insn_queue; | |
1081 | else if (other_queue != NULL) | |
1082 | queue = &other_queue; | |
1083 | else | |
1084 | return NULL_RTX; | |
1085 | ||
1086 | elem = *queue; | |
1087 | *queue = elem->next; | |
1088 | desc = elem->data; | |
f1c96ec2 | 1089 | read_rtx_filename = elem->filename; |
1df8f1eb | 1090 | *lineno = elem->lineno; |
c5ddd6b5 | 1091 | *seqnr = sequence_num; |
1df8f1eb | 1092 | |
1093 | free (elem); | |
1094 | ||
b70bd542 | 1095 | /* Discard insn patterns which we know can never match (because |
1096 | their C test is provably always false). If insn_elision is | |
1097 | false, our caller needs to see all the patterns. Note that the | |
1098 | elided patterns are never counted by the sequence numbering; it | |
1099 | it is the caller's responsibility, when insn_elision is false, not | |
1100 | to use elided pattern numbers for anything. */ | |
c5ddd6b5 | 1101 | switch (GET_CODE (desc)) |
1102 | { | |
1df8f1eb | 1103 | case DEFINE_INSN: |
1104 | case DEFINE_EXPAND: | |
b70bd542 | 1105 | if (maybe_eval_c_test (XSTR (desc, 2)) != 0) |
1106 | sequence_num++; | |
1107 | else if (insn_elision) | |
1108 | goto discard; | |
343695df | 1109 | |
1110 | /* *seqnr is used here so the name table will match caller's | |
1111 | idea of insn numbering, whether or not elision is active. */ | |
1112 | record_insn_name (*seqnr, XSTR (desc, 0)); | |
b70bd542 | 1113 | break; |
1114 | ||
1df8f1eb | 1115 | case DEFINE_SPLIT: |
1116 | case DEFINE_PEEPHOLE: | |
1117 | case DEFINE_PEEPHOLE2: | |
b70bd542 | 1118 | if (maybe_eval_c_test (XSTR (desc, 1)) != 0) |
1119 | sequence_num++; | |
1120 | else if (insn_elision) | |
1121 | goto discard; | |
1df8f1eb | 1122 | break; |
1123 | ||
1124 | default: | |
1125 | break; | |
c5ddd6b5 | 1126 | } |
1127 | ||
1128 | return desc; | |
1129 | } | |
be46690e | 1130 | |
b70bd542 | 1131 | /* Helper functions for insn elision. */ |
1132 | ||
1133 | /* Compute a hash function of a c_test structure, which is keyed | |
1134 | by its ->expr field. */ | |
1135 | hashval_t | |
1a97be37 | 1136 | hash_c_test (const void *x) |
b70bd542 | 1137 | { |
1138 | const struct c_test *a = (const struct c_test *) x; | |
1139 | const unsigned char *base, *s = (const unsigned char *) a->expr; | |
1140 | hashval_t hash; | |
1141 | unsigned char c; | |
1142 | unsigned int len; | |
1143 | ||
1144 | base = s; | |
1145 | hash = 0; | |
1146 | ||
1147 | while ((c = *s++) != '\0') | |
1148 | { | |
1149 | hash += c + (c << 17); | |
1150 | hash ^= hash >> 2; | |
1151 | } | |
1152 | ||
1153 | len = s - base; | |
1154 | hash += len + (len << 17); | |
1155 | hash ^= hash >> 2; | |
1156 | ||
1157 | return hash; | |
1158 | } | |
1159 | ||
1160 | /* Compare two c_test expression structures. */ | |
1161 | int | |
1a97be37 | 1162 | cmp_c_test (const void *x, const void *y) |
b70bd542 | 1163 | { |
1164 | const struct c_test *a = (const struct c_test *) x; | |
1165 | const struct c_test *b = (const struct c_test *) y; | |
1166 | ||
1167 | return !strcmp (a->expr, b->expr); | |
1168 | } | |
1169 | ||
1170 | /* Given a string representing a C test expression, look it up in the | |
1171 | condition_table and report whether or not its value is known | |
1172 | at compile time. Returns a tristate: 1 for known true, 0 for | |
1173 | known false, -1 for unknown. */ | |
1174 | int | |
1a97be37 | 1175 | maybe_eval_c_test (const char *expr) |
b70bd542 | 1176 | { |
1177 | const struct c_test *test; | |
1178 | struct c_test dummy; | |
1179 | ||
1180 | if (expr[0] == 0) | |
1181 | return 1; | |
1182 | ||
b70bd542 | 1183 | dummy.expr = expr; |
9318f22c | 1184 | test = (const struct c_test *)htab_find (condition_table, &dummy); |
af908c02 | 1185 | if (!test) |
1186 | return -1; | |
b70bd542 | 1187 | return test->value; |
1188 | } | |
1189 | ||
af908c02 | 1190 | /* Record the C test expression EXPR in the condition_table, with |
1191 | value VAL. Duplicates clobber previous entries. */ | |
1192 | ||
1193 | void | |
1194 | add_c_test (const char *expr, int value) | |
1195 | { | |
1196 | struct c_test *test; | |
1197 | ||
1198 | if (expr[0] == 0) | |
1199 | return; | |
1200 | ||
1201 | test = XNEW (struct c_test); | |
1202 | test->expr = expr; | |
1203 | test->value = value; | |
1204 | ||
1205 | *(htab_find_slot (condition_table, test, INSERT)) = test; | |
1206 | } | |
1207 | ||
1208 | /* For every C test, call CALLBACK with two arguments: a pointer to | |
1209 | the condition structure and INFO. Stops when CALLBACK returns zero. */ | |
1210 | void | |
1211 | traverse_c_tests (htab_trav callback, void *info) | |
1212 | { | |
1213 | if (condition_table) | |
1214 | htab_traverse (condition_table, callback, info); | |
1215 | } | |
1216 | ||
cbf464bd | 1217 | /* Helper functions for define_predicate and define_special_predicate |
1218 | processing. Shared between genrecog.c and genpreds.c. */ | |
1219 | ||
1220 | static htab_t predicate_table; | |
1221 | struct pred_data *first_predicate; | |
1222 | static struct pred_data **last_predicate = &first_predicate; | |
1223 | ||
1224 | static hashval_t | |
1225 | hash_struct_pred_data (const void *ptr) | |
1226 | { | |
1227 | return htab_hash_string (((const struct pred_data *)ptr)->name); | |
1228 | } | |
1229 | ||
1230 | static int | |
1231 | eq_struct_pred_data (const void *a, const void *b) | |
1232 | { | |
1233 | return !strcmp (((const struct pred_data *)a)->name, | |
1234 | ((const struct pred_data *)b)->name); | |
1235 | } | |
1236 | ||
1237 | struct pred_data * | |
1238 | lookup_predicate (const char *name) | |
1239 | { | |
1240 | struct pred_data key; | |
1241 | key.name = name; | |
a9c6c0e3 | 1242 | return (struct pred_data *) htab_find (predicate_table, &key); |
cbf464bd | 1243 | } |
1244 | ||
c7a4c804 | 1245 | /* Record that predicate PRED can accept CODE. */ |
1246 | ||
1247 | void | |
1248 | add_predicate_code (struct pred_data *pred, enum rtx_code code) | |
1249 | { | |
1250 | if (!pred->codes[code]) | |
1251 | { | |
1252 | pred->num_codes++; | |
1253 | pred->codes[code] = true; | |
1254 | ||
1255 | if (GET_RTX_CLASS (code) != RTX_CONST_OBJ) | |
1256 | pred->allows_non_const = true; | |
1257 | ||
1258 | if (code != REG | |
1259 | && code != SUBREG | |
1260 | && code != MEM | |
1261 | && code != CONCAT | |
1262 | && code != PARALLEL | |
1263 | && code != STRICT_LOW_PART) | |
1264 | pred->allows_non_lvalue = true; | |
1265 | ||
1266 | if (pred->num_codes == 1) | |
1267 | pred->singleton = code; | |
1268 | else if (pred->num_codes == 2) | |
1269 | pred->singleton = UNKNOWN; | |
1270 | } | |
1271 | } | |
1272 | ||
cbf464bd | 1273 | void |
1274 | add_predicate (struct pred_data *pred) | |
1275 | { | |
1276 | void **slot = htab_find_slot (predicate_table, pred, INSERT); | |
1277 | if (*slot) | |
1278 | { | |
1279 | error ("duplicate predicate definition for '%s'", pred->name); | |
1280 | return; | |
1281 | } | |
1282 | *slot = pred; | |
1283 | *last_predicate = pred; | |
1284 | last_predicate = &pred->next; | |
1285 | } | |
1286 | ||
1287 | /* This array gives the initial content of the predicate table. It | |
63dfe6b8 | 1288 | has entries for all predicates defined in recog.c. */ |
cbf464bd | 1289 | |
dd536ba1 | 1290 | struct std_pred_table |
cbf464bd | 1291 | { |
1292 | const char *name; | |
dd536ba1 | 1293 | bool special; |
c7a4c804 | 1294 | bool allows_const_p; |
cbf464bd | 1295 | RTX_CODE codes[NUM_RTX_CODE]; |
1296 | }; | |
1297 | ||
dd536ba1 | 1298 | static const struct std_pred_table std_preds[] = { |
c7a4c804 | 1299 | {"general_operand", false, true, {SUBREG, REG, MEM}}, |
1300 | {"address_operand", true, true, {SUBREG, REG, MEM, PLUS, MINUS, MULT}}, | |
1301 | {"register_operand", false, false, {SUBREG, REG}}, | |
1302 | {"pmode_register_operand", true, false, {SUBREG, REG}}, | |
1303 | {"scratch_operand", false, false, {SCRATCH, REG}}, | |
bc620c5c | 1304 | {"immediate_operand", false, true, {UNKNOWN}}, |
c7a4c804 | 1305 | {"const_int_operand", false, false, {CONST_INT}}, |
1306 | {"const_double_operand", false, false, {CONST_INT, CONST_DOUBLE}}, | |
1307 | {"nonimmediate_operand", false, false, {SUBREG, REG, MEM}}, | |
1308 | {"nonmemory_operand", false, true, {SUBREG, REG}}, | |
1309 | {"push_operand", false, false, {MEM}}, | |
1310 | {"pop_operand", false, false, {MEM}}, | |
1311 | {"memory_operand", false, false, {SUBREG, MEM}}, | |
1312 | {"indirect_operand", false, false, {SUBREG, MEM}}, | |
c429965c | 1313 | {"ordered_comparison_operator", false, false, {EQ, NE, |
1314 | LE, LT, GE, GT, | |
1315 | LEU, LTU, GEU, GTU}}, | |
c7a4c804 | 1316 | {"comparison_operator", false, false, {EQ, NE, |
1317 | LE, LT, GE, GT, | |
1318 | LEU, LTU, GEU, GTU, | |
1319 | UNORDERED, ORDERED, | |
1320 | UNEQ, UNGE, UNGT, | |
1321 | UNLE, UNLT, LTGT}} | |
cbf464bd | 1322 | }; |
dd536ba1 | 1323 | #define NUM_KNOWN_STD_PREDS ARRAY_SIZE (std_preds) |
cbf464bd | 1324 | |
1325 | /* Initialize the table of predicate definitions, starting with | |
63dfe6b8 | 1326 | the information we have on generic predicates. */ |
cbf464bd | 1327 | |
1328 | static void | |
1329 | init_predicate_table (void) | |
1330 | { | |
1331 | size_t i, j; | |
1332 | struct pred_data *pred; | |
1333 | ||
1334 | predicate_table = htab_create_alloc (37, hash_struct_pred_data, | |
1335 | eq_struct_pred_data, 0, | |
1336 | xcalloc, free); | |
1337 | ||
dd536ba1 | 1338 | for (i = 0; i < NUM_KNOWN_STD_PREDS; i++) |
cbf464bd | 1339 | { |
a9c6c0e3 | 1340 | pred = XCNEW (struct pred_data); |
dd536ba1 | 1341 | pred->name = std_preds[i].name; |
1342 | pred->special = std_preds[i].special; | |
cbf464bd | 1343 | |
dd536ba1 | 1344 | for (j = 0; std_preds[i].codes[j] != 0; j++) |
c7a4c804 | 1345 | add_predicate_code (pred, std_preds[i].codes[j]); |
1346 | ||
1347 | if (std_preds[i].allows_const_p) | |
1348 | for (j = 0; j < NUM_RTX_CODE; j++) | |
1349 | if (GET_RTX_CLASS (j) == RTX_CONST_OBJ) | |
b9c74b4d | 1350 | add_predicate_code (pred, (enum rtx_code) j); |
48e1416a | 1351 | |
cbf464bd | 1352 | add_predicate (pred); |
1353 | } | |
cbf464bd | 1354 | } |
343695df | 1355 | \f |
1356 | /* These functions allow linkage with print-rtl.c. Also, some generators | |
1357 | like to annotate their output with insn names. */ | |
1358 | ||
1359 | /* Holds an array of names indexed by insn_code_number. */ | |
1360 | static char **insn_name_ptr = 0; | |
1361 | static int insn_name_ptr_size = 0; | |
1362 | ||
1363 | const char * | |
1364 | get_insn_name (int code) | |
1365 | { | |
1366 | if (code < insn_name_ptr_size) | |
1367 | return insn_name_ptr[code]; | |
1368 | else | |
1369 | return NULL; | |
1370 | } | |
1371 | ||
1372 | static void | |
1373 | record_insn_name (int code, const char *name) | |
1374 | { | |
1375 | static const char *last_real_name = "insn"; | |
1376 | static int last_real_code = 0; | |
2657a7d5 | 1377 | char *new_name; |
343695df | 1378 | |
1379 | if (insn_name_ptr_size <= code) | |
1380 | { | |
1381 | int new_size; | |
1382 | new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512); | |
65b198c2 | 1383 | insn_name_ptr = XRESIZEVEC (char *, insn_name_ptr, new_size); |
343695df | 1384 | memset (insn_name_ptr + insn_name_ptr_size, 0, |
1385 | sizeof(char *) * (new_size - insn_name_ptr_size)); | |
1386 | insn_name_ptr_size = new_size; | |
1387 | } | |
1388 | ||
1389 | if (!name || name[0] == '\0') | |
1390 | { | |
2657a7d5 | 1391 | new_name = XNEWVAR (char, strlen (last_real_name) + 10); |
1392 | sprintf (new_name, "%s+%d", last_real_name, code - last_real_code); | |
343695df | 1393 | } |
1394 | else | |
1395 | { | |
2657a7d5 | 1396 | last_real_name = new_name = xstrdup (name); |
343695df | 1397 | last_real_code = code; |
1398 | } | |
1399 | ||
2657a7d5 | 1400 | insn_name_ptr[code] = new_name; |
343695df | 1401 | } |