]>
Commit | Line | Data |
---|---|---|
bccafa26 | 1 | /* RTL reader for GCC. |
3ad4992f | 2 | Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000, 2001, 2002, |
d91f7526 | 3 | 2003, 2004, 2005, 2007, 2008, 2010 |
875d8740 | 4 | Free Software Foundation, Inc. |
5 | ||
f12b58b3 | 6 | This file is part of GCC. |
875d8740 | 7 | |
f12b58b3 | 8 | GCC is free software; you can redistribute it and/or modify it under |
9 | the terms of the GNU General Public License as published by the Free | |
8c4c00c1 | 10 | Software Foundation; either version 3, or (at your option) any later |
f12b58b3 | 11 | version. |
875d8740 | 12 | |
f12b58b3 | 13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | for more details. | |
875d8740 | 17 | |
18 | You should have received a copy of the GNU General Public License | |
8c4c00c1 | 19 | along with GCC; see the file COPYING3. If not see |
20 | <http://www.gnu.org/licenses/>. */ | |
875d8740 | 21 | |
805e22b2 | 22 | #include "bconfig.h" |
4f1159f8 | 23 | |
fd781bb2 | 24 | /* Disable rtl checking; it conflicts with the iterator handling. */ |
4f1159f8 | 25 | #undef ENABLE_RTL_CHECKING |
26 | ||
875d8740 | 27 | #include "system.h" |
805e22b2 | 28 | #include "coretypes.h" |
29 | #include "tm.h" | |
875d8740 | 30 | #include "rtl.h" |
31 | #include "obstack.h" | |
32 | #include "hashtab.h" | |
960ebfe7 | 33 | #include "read-md.h" |
af908c02 | 34 | #include "gensupport.h" |
875d8740 | 35 | |
4a293229 | 36 | /* One element in a singly-linked list of (integer, string) pairs. */ |
37 | struct map_value { | |
38 | struct map_value *next; | |
39 | int number; | |
40 | const char *string; | |
41 | }; | |
42 | ||
fd781bb2 | 43 | /* Maps an iterator or attribute name to a list of (integer, string) pairs. |
f5d566ff | 44 | The integers are iterator values; the strings are either C conditions |
4a293229 | 45 | or attribute values. */ |
46 | struct mapping { | |
fd781bb2 | 47 | /* The name of the iterator or attribute. */ |
4a293229 | 48 | const char *name; |
49 | ||
fd781bb2 | 50 | /* The group (modes or codes) to which the iterator or attribute belongs. */ |
51 | struct iterator_group *group; | |
4a293229 | 52 | |
4a293229 | 53 | /* The list of (integer, string) pairs. */ |
54 | struct map_value *values; | |
f5d566ff | 55 | |
56 | /* For iterators, records the current value of the iterator. */ | |
57 | struct map_value *current_value; | |
4a293229 | 58 | }; |
59 | ||
f5d566ff | 60 | /* Vector definitions for the above. */ |
61 | typedef struct mapping *mapping_ptr; | |
f5d566ff | 62 | |
63 | /* A structure for abstracting the common parts of iterators. */ | |
fd781bb2 | 64 | struct iterator_group { |
f5d566ff | 65 | /* Tables of "mapping" structures, one for attributes and one for |
66 | iterators. */ | |
fd781bb2 | 67 | htab_t attrs, iterators; |
4a293229 | 68 | |
f5d566ff | 69 | /* Treat the given string as the name of a standard mode, etc., and |
b3453c30 | 70 | return its integer value. */ |
71 | int (*find_builtin) (const char *); | |
4a293229 | 72 | |
f5d566ff | 73 | /* Make the given pointer use the given iterator value. */ |
74 | void (*apply_iterator) (void *, int); | |
75 | }; | |
4a293229 | 76 | |
f5d566ff | 77 | /* Records one use of an iterator. */ |
78 | struct iterator_use { | |
79 | /* The iterator itself. */ | |
80 | struct mapping *iterator; | |
81 | ||
82 | /* The location of the use, as passed to the apply_iterator callback. */ | |
83 | void *ptr; | |
4a293229 | 84 | }; |
85 | ||
f5d566ff | 86 | /* Vector definitions for the above. */ |
87 | typedef struct iterator_use iterator_use; | |
f5d566ff | 88 | |
89 | /* Records one use of an attribute (the "<[iterator:]attribute>" syntax) | |
90 | in a non-string rtx field. */ | |
91 | struct attribute_use { | |
92 | /* The group that describes the use site. */ | |
93 | struct iterator_group *group; | |
94 | ||
95 | /* The name of the attribute, possibly with an "iterator:" prefix. */ | |
96 | const char *value; | |
97 | ||
98 | /* The location of the use, as passed to GROUP's apply_iterator callback. */ | |
99 | void *ptr; | |
e64e4ed9 | 100 | }; |
101 | ||
f5d566ff | 102 | /* Vector definitions for the above. */ |
103 | typedef struct attribute_use attribute_use; | |
f5d566ff | 104 | |
b3453c30 | 105 | static void validate_const_int (const char *); |
f5d566ff | 106 | static rtx read_rtx_code (const char *); |
107 | static rtx read_nested_rtx (void); | |
108 | static rtx read_rtx_variadic (rtx); | |
4a293229 | 109 | |
fd781bb2 | 110 | /* The mode and code iterator structures. */ |
65729bd0 | 111 | static struct iterator_group modes, codes, ints; |
4a293229 | 112 | |
f5d566ff | 113 | /* All iterators used in the current rtx. */ |
f1f41a6c | 114 | static vec<mapping_ptr> current_iterators; |
f5d566ff | 115 | |
116 | /* The list of all iterator uses in the current rtx. */ | |
f1f41a6c | 117 | static vec<iterator_use> iterator_uses; |
f5d566ff | 118 | |
119 | /* The list of all attribute uses in the current rtx. */ | |
f1f41a6c | 120 | static vec<attribute_use> attribute_uses; |
875d8740 | 121 | |
fd781bb2 | 122 | /* Implementations of the iterator_group callbacks for modes. */ |
4a293229 | 123 | |
124 | static int | |
b3453c30 | 125 | find_mode (const char *name) |
4a293229 | 126 | { |
127 | int i; | |
128 | ||
129 | for (i = 0; i < NUM_MACHINE_MODES; i++) | |
130 | if (strcmp (GET_MODE_NAME (i), name) == 0) | |
131 | return i; | |
132 | ||
b3453c30 | 133 | fatal_with_file_and_line ("unknown mode `%s'", name); |
4a293229 | 134 | } |
135 | ||
4a293229 | 136 | static void |
f5d566ff | 137 | apply_mode_iterator (void *loc, int mode) |
4a293229 | 138 | { |
f5d566ff | 139 | PUT_MODE ((rtx) loc, (enum machine_mode) mode); |
4a293229 | 140 | } |
141 | ||
fd781bb2 | 142 | /* Implementations of the iterator_group callbacks for codes. */ |
4a293229 | 143 | |
144 | static int | |
b3453c30 | 145 | find_code (const char *name) |
4a293229 | 146 | { |
147 | int i; | |
148 | ||
149 | for (i = 0; i < NUM_RTX_CODE; i++) | |
150 | if (strcmp (GET_RTX_NAME (i), name) == 0) | |
151 | return i; | |
152 | ||
b3453c30 | 153 | fatal_with_file_and_line ("unknown rtx code `%s'", name); |
4a293229 | 154 | } |
155 | ||
4a293229 | 156 | static void |
f5d566ff | 157 | apply_code_iterator (void *loc, int code) |
4a293229 | 158 | { |
f5d566ff | 159 | PUT_CODE ((rtx) loc, (enum rtx_code) code); |
4a293229 | 160 | } |
161 | ||
65729bd0 | 162 | /* Implementations of the iterator_group callbacks for ints. */ |
163 | ||
164 | /* Since GCC does not construct a table of valid constants, | |
165 | we have to accept any int as valid. No cross-checking can | |
166 | be done. */ | |
167 | ||
168 | static int | |
169 | find_int (const char *name) | |
170 | { | |
171 | validate_const_int (name); | |
172 | return atoi (name); | |
173 | } | |
174 | ||
175 | static void | |
176 | apply_int_iterator (void *loc, int value) | |
177 | { | |
178 | *(int *)loc = value; | |
179 | } | |
180 | ||
f5d566ff | 181 | /* Map attribute string P to its current value. Return null if the attribute |
182 | isn't known. */ | |
e64e4ed9 | 183 | |
184 | static struct map_value * | |
f5d566ff | 185 | map_attr_string (const char *p) |
e64e4ed9 | 186 | { |
187 | const char *attr; | |
f5d566ff | 188 | struct mapping *iterator; |
189 | unsigned int i; | |
e64e4ed9 | 190 | struct mapping *m; |
191 | struct map_value *v; | |
f5d566ff | 192 | int iterator_name_len; |
e64e4ed9 | 193 | |
f5d566ff | 194 | /* Peel off any "iterator:" prefix. Set ATTR to the start of the |
195 | attribute name. */ | |
e64e4ed9 | 196 | attr = strchr (p, ':'); |
197 | if (attr == 0) | |
f5d566ff | 198 | { |
199 | iterator_name_len = -1; | |
200 | attr = p; | |
201 | } | |
e64e4ed9 | 202 | else |
203 | { | |
f5d566ff | 204 | iterator_name_len = attr - p; |
e64e4ed9 | 205 | attr++; |
206 | } | |
207 | ||
f1f41a6c | 208 | FOR_EACH_VEC_ELT (current_iterators, i, iterator) |
e64e4ed9 | 209 | { |
f5d566ff | 210 | /* If an iterator name was specified, check that it matches. */ |
211 | if (iterator_name_len >= 0 | |
212 | && (strncmp (p, iterator->name, iterator_name_len) != 0 | |
213 | || iterator->name[iterator_name_len] != 0)) | |
214 | continue; | |
e64e4ed9 | 215 | |
f5d566ff | 216 | /* Find the attribute specification. */ |
217 | m = (struct mapping *) htab_find (iterator->group->attrs, &attr); | |
218 | if (m) | |
219 | /* Find the attribute value associated with the current | |
220 | iterator value. */ | |
221 | for (v = m->values; v; v = v->next) | |
222 | if (v->number == iterator->current_value->number) | |
223 | return v; | |
e64e4ed9 | 224 | } |
f5d566ff | 225 | return NULL; |
e64e4ed9 | 226 | } |
227 | ||
f5d566ff | 228 | /* Apply the current iterator values to STRING. Return the new string |
229 | if any changes were needed, otherwise return STRING itself. */ | |
4a293229 | 230 | |
231 | static const char * | |
f5d566ff | 232 | apply_iterator_to_string (const char *string) |
4a293229 | 233 | { |
e64e4ed9 | 234 | char *base, *copy, *p, *start, *end; |
4a293229 | 235 | struct map_value *v; |
236 | ||
237 | if (string == 0) | |
238 | return string; | |
239 | ||
240 | base = p = copy = ASTRDUP (string); | |
192342fa | 241 | while ((start = strchr (p, '<')) && (end = strchr (start, '>'))) |
4a293229 | 242 | { |
243 | p = start + 1; | |
244 | ||
4a293229 | 245 | *end = 0; |
f5d566ff | 246 | v = map_attr_string (p); |
4a293229 | 247 | *end = '>'; |
4a293229 | 248 | if (v == 0) |
249 | continue; | |
250 | ||
251 | /* Add everything between the last copied byte and the '<', | |
252 | then add in the attribute value. */ | |
253 | obstack_grow (&string_obstack, base, start - base); | |
254 | obstack_grow (&string_obstack, v->string, strlen (v->string)); | |
255 | base = end + 1; | |
256 | } | |
257 | if (base != copy) | |
258 | { | |
259 | obstack_grow (&string_obstack, base, strlen (base) + 1); | |
4fac984f | 260 | copy = XOBFINISH (&string_obstack, char *); |
77c2564f | 261 | copy_md_ptr_loc (copy, string); |
9e959634 | 262 | return copy; |
4a293229 | 263 | } |
264 | return string; | |
265 | } | |
266 | ||
f5d566ff | 267 | /* Return a deep copy of X, substituting the current iterator |
268 | values into any strings. */ | |
4a293229 | 269 | |
270 | static rtx | |
f5d566ff | 271 | copy_rtx_for_iterators (rtx original) |
4a293229 | 272 | { |
4a293229 | 273 | const char *format_ptr; |
274 | int i, j; | |
275 | rtx x; | |
4a293229 | 276 | |
277 | if (original == 0) | |
278 | return original; | |
279 | ||
280 | /* Create a shallow copy of ORIGINAL. */ | |
f5d566ff | 281 | x = rtx_alloc (GET_CODE (original)); |
282 | memcpy (x, original, RTX_CODE_SIZE (GET_CODE (original))); | |
e64e4ed9 | 283 | |
4a293229 | 284 | /* Change each string and recursively change each rtx. */ |
f5d566ff | 285 | format_ptr = GET_RTX_FORMAT (GET_CODE (original)); |
4a293229 | 286 | for (i = 0; format_ptr[i] != 0; i++) |
287 | switch (format_ptr[i]) | |
288 | { | |
4a293229 | 289 | case 'T': |
f5d566ff | 290 | XTMPL (x, i) = apply_iterator_to_string (XTMPL (x, i)); |
4f1159f8 | 291 | break; |
292 | ||
293 | case 'S': | |
4a293229 | 294 | case 's': |
f5d566ff | 295 | XSTR (x, i) = apply_iterator_to_string (XSTR (x, i)); |
4a293229 | 296 | break; |
297 | ||
298 | case 'e': | |
f5d566ff | 299 | XEXP (x, i) = copy_rtx_for_iterators (XEXP (x, i)); |
4a293229 | 300 | break; |
301 | ||
302 | case 'V': | |
303 | case 'E': | |
304 | if (XVEC (original, i)) | |
305 | { | |
306 | XVEC (x, i) = rtvec_alloc (XVECLEN (original, i)); | |
307 | for (j = 0; j < XVECLEN (x, i); j++) | |
f5d566ff | 308 | XVECEXP (x, i, j) |
309 | = copy_rtx_for_iterators (XVECEXP (original, i, j)); | |
4a293229 | 310 | } |
311 | break; | |
312 | ||
313 | default: | |
314 | break; | |
315 | } | |
316 | return x; | |
317 | } | |
318 | ||
4a293229 | 319 | /* Return a condition that must satisfy both ORIGINAL and EXTRA. If ORIGINAL |
320 | has the form "&& ..." (as used in define_insn_and_splits), assume that | |
321 | EXTRA is already satisfied. Empty strings are treated like "true". */ | |
322 | ||
323 | static const char * | |
324 | add_condition_to_string (const char *original, const char *extra) | |
325 | { | |
9e959634 | 326 | if (original != 0 && original[0] == '&' && original[1] == '&') |
4a293229 | 327 | return original; |
9e959634 | 328 | return join_c_conditions (original, extra); |
4a293229 | 329 | } |
330 | ||
331 | /* Like add_condition, but applied to all conditions in rtx X. */ | |
332 | ||
333 | static void | |
334 | add_condition_to_rtx (rtx x, const char *extra) | |
335 | { | |
336 | switch (GET_CODE (x)) | |
337 | { | |
338 | case DEFINE_INSN: | |
339 | case DEFINE_EXPAND: | |
340 | XSTR (x, 2) = add_condition_to_string (XSTR (x, 2), extra); | |
341 | break; | |
342 | ||
343 | case DEFINE_SPLIT: | |
344 | case DEFINE_PEEPHOLE: | |
345 | case DEFINE_PEEPHOLE2: | |
346 | case DEFINE_COND_EXEC: | |
347 | XSTR (x, 1) = add_condition_to_string (XSTR (x, 1), extra); | |
348 | break; | |
349 | ||
350 | case DEFINE_INSN_AND_SPLIT: | |
351 | XSTR (x, 2) = add_condition_to_string (XSTR (x, 2), extra); | |
352 | XSTR (x, 4) = add_condition_to_string (XSTR (x, 4), extra); | |
353 | break; | |
354 | ||
355 | default: | |
356 | break; | |
357 | } | |
358 | } | |
359 | ||
f5d566ff | 360 | /* Apply the current iterator values to all attribute_uses. */ |
361 | ||
362 | static void | |
363 | apply_attribute_uses (void) | |
364 | { | |
365 | struct map_value *v; | |
366 | attribute_use *ause; | |
367 | unsigned int i; | |
368 | ||
f1f41a6c | 369 | FOR_EACH_VEC_ELT (attribute_uses, i, ause) |
f5d566ff | 370 | { |
371 | v = map_attr_string (ause->value); | |
372 | if (!v) | |
373 | fatal_with_file_and_line ("unknown iterator value `%s'", ause->value); | |
374 | ause->group->apply_iterator (ause->ptr, | |
375 | ause->group->find_builtin (v->string)); | |
376 | } | |
377 | } | |
378 | ||
379 | /* A htab_traverse callback for iterators. Add all used iterators | |
380 | to current_iterators. */ | |
4a293229 | 381 | |
382 | static int | |
f5d566ff | 383 | add_current_iterators (void **slot, void *data ATTRIBUTE_UNUSED) |
4a293229 | 384 | { |
fd781bb2 | 385 | struct mapping *iterator; |
4a293229 | 386 | |
fd781bb2 | 387 | iterator = (struct mapping *) *slot; |
f5d566ff | 388 | if (iterator->current_value) |
f1f41a6c | 389 | current_iterators.safe_push (iterator); |
4a293229 | 390 | return 1; |
391 | } | |
392 | ||
f5d566ff | 393 | /* Expand all iterators in the current rtx, which is given as ORIGINAL. |
394 | Build a list of expanded rtxes in the EXPR_LIST pointed to by QUEUE. */ | |
395 | ||
396 | static void | |
397 | apply_iterators (rtx original, rtx *queue) | |
398 | { | |
399 | unsigned int i; | |
400 | const char *condition; | |
401 | iterator_use *iuse; | |
402 | struct mapping *iterator; | |
403 | struct map_value *v; | |
404 | rtx x; | |
405 | ||
f1f41a6c | 406 | if (iterator_uses.is_empty ()) |
f5d566ff | 407 | { |
408 | /* Raise an error if any attributes were used. */ | |
409 | apply_attribute_uses (); | |
410 | XEXP (*queue, 0) = original; | |
411 | XEXP (*queue, 1) = NULL_RTX; | |
412 | return; | |
413 | } | |
414 | ||
415 | /* Clear out the iterators from the previous run. */ | |
f1f41a6c | 416 | FOR_EACH_VEC_ELT (current_iterators, i, iterator) |
f5d566ff | 417 | iterator->current_value = NULL; |
f1f41a6c | 418 | current_iterators.truncate (0); |
f5d566ff | 419 | |
420 | /* Mark the iterators that we need this time. */ | |
f1f41a6c | 421 | FOR_EACH_VEC_ELT (iterator_uses, i, iuse) |
f5d566ff | 422 | iuse->iterator->current_value = iuse->iterator->values; |
423 | ||
424 | /* Get the list of iterators that are in use, preserving the | |
425 | definition order within each group. */ | |
426 | htab_traverse (modes.iterators, add_current_iterators, NULL); | |
427 | htab_traverse (codes.iterators, add_current_iterators, NULL); | |
65729bd0 | 428 | htab_traverse (ints.iterators, add_current_iterators, NULL); |
f1f41a6c | 429 | gcc_assert (!current_iterators.is_empty ()); |
f5d566ff | 430 | |
431 | for (;;) | |
432 | { | |
433 | /* Apply the current iterator values. Accumulate a condition to | |
434 | say when the resulting rtx can be used. */ | |
435 | condition = NULL; | |
f1f41a6c | 436 | FOR_EACH_VEC_ELT (iterator_uses, i, iuse) |
f5d566ff | 437 | { |
438 | v = iuse->iterator->current_value; | |
439 | iuse->iterator->group->apply_iterator (iuse->ptr, v->number); | |
440 | condition = join_c_conditions (condition, v->string); | |
441 | } | |
442 | apply_attribute_uses (); | |
443 | x = copy_rtx_for_iterators (original); | |
444 | add_condition_to_rtx (x, condition); | |
445 | ||
446 | /* Add the new rtx to the end of the queue. */ | |
447 | XEXP (*queue, 0) = x; | |
448 | XEXP (*queue, 1) = NULL_RTX; | |
449 | ||
450 | /* Lexicographically increment the iterator value sequence. | |
451 | That is, cycle through iterator values, starting from the right, | |
452 | and stopping when one of them doesn't wrap around. */ | |
f1f41a6c | 453 | i = current_iterators.length (); |
f5d566ff | 454 | for (;;) |
455 | { | |
456 | if (i == 0) | |
457 | return; | |
458 | i--; | |
f1f41a6c | 459 | iterator = current_iterators[i]; |
f5d566ff | 460 | iterator->current_value = iterator->current_value->next; |
461 | if (iterator->current_value) | |
462 | break; | |
463 | iterator->current_value = iterator->values; | |
464 | } | |
465 | ||
466 | /* At least one more rtx to go. Allocate room for it. */ | |
467 | XEXP (*queue, 1) = rtx_alloc (EXPR_LIST); | |
468 | queue = &XEXP (*queue, 1); | |
469 | } | |
470 | } | |
471 | ||
4a293229 | 472 | /* Add a new "mapping" structure to hashtable TABLE. NAME is the name |
b3453c30 | 473 | of the mapping and GROUP is the group to which it belongs. */ |
4a293229 | 474 | |
475 | static struct mapping * | |
b3453c30 | 476 | add_mapping (struct iterator_group *group, htab_t table, const char *name) |
4a293229 | 477 | { |
478 | struct mapping *m; | |
479 | void **slot; | |
480 | ||
481 | m = XNEW (struct mapping); | |
482 | m->name = xstrdup (name); | |
483 | m->group = group; | |
4a293229 | 484 | m->values = 0; |
f5d566ff | 485 | m->current_value = NULL; |
4a293229 | 486 | |
487 | slot = htab_find_slot (table, m, INSERT); | |
488 | if (*slot != 0) | |
b3453c30 | 489 | fatal_with_file_and_line ("`%s' already defined", name); |
4a293229 | 490 | |
491 | *slot = m; | |
492 | return m; | |
493 | } | |
494 | ||
495 | /* Add the pair (NUMBER, STRING) to a list of map_value structures. | |
496 | END_PTR points to the current null terminator for the list; return | |
497 | a pointer the new null terminator. */ | |
498 | ||
499 | static struct map_value ** | |
500 | add_map_value (struct map_value **end_ptr, int number, const char *string) | |
501 | { | |
502 | struct map_value *value; | |
503 | ||
504 | value = XNEW (struct map_value); | |
505 | value->next = 0; | |
506 | value->number = number; | |
507 | value->string = string; | |
508 | ||
509 | *end_ptr = value; | |
510 | return &value->next; | |
511 | } | |
512 | ||
513 | /* Do one-time initialization of the mode and code attributes. */ | |
514 | ||
515 | static void | |
fd781bb2 | 516 | initialize_iterators (void) |
4a293229 | 517 | { |
518 | struct mapping *lower, *upper; | |
519 | struct map_value **lower_ptr, **upper_ptr; | |
520 | char *copy, *p; | |
521 | int i; | |
522 | ||
ac0640e5 | 523 | modes.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0); |
524 | modes.iterators = htab_create (13, leading_string_hash, | |
525 | leading_string_eq_p, 0); | |
4a293229 | 526 | modes.find_builtin = find_mode; |
fd781bb2 | 527 | modes.apply_iterator = apply_mode_iterator; |
4a293229 | 528 | |
ac0640e5 | 529 | codes.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0); |
530 | codes.iterators = htab_create (13, leading_string_hash, | |
531 | leading_string_eq_p, 0); | |
4a293229 | 532 | codes.find_builtin = find_code; |
fd781bb2 | 533 | codes.apply_iterator = apply_code_iterator; |
4a293229 | 534 | |
65729bd0 | 535 | ints.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0); |
536 | ints.iterators = htab_create (13, leading_string_hash, | |
537 | leading_string_eq_p, 0); | |
538 | ints.find_builtin = find_int; | |
539 | ints.apply_iterator = apply_int_iterator; | |
540 | ||
b3453c30 | 541 | lower = add_mapping (&modes, modes.attrs, "mode"); |
542 | upper = add_mapping (&modes, modes.attrs, "MODE"); | |
4a293229 | 543 | lower_ptr = &lower->values; |
544 | upper_ptr = &upper->values; | |
545 | for (i = 0; i < MAX_MACHINE_MODE; i++) | |
546 | { | |
547 | copy = xstrdup (GET_MODE_NAME (i)); | |
548 | for (p = copy; *p != 0; p++) | |
549 | *p = TOLOWER (*p); | |
550 | ||
551 | upper_ptr = add_map_value (upper_ptr, i, GET_MODE_NAME (i)); | |
552 | lower_ptr = add_map_value (lower_ptr, i, copy); | |
553 | } | |
554 | ||
b3453c30 | 555 | lower = add_mapping (&codes, codes.attrs, "code"); |
556 | upper = add_mapping (&codes, codes.attrs, "CODE"); | |
4a293229 | 557 | lower_ptr = &lower->values; |
558 | upper_ptr = &upper->values; | |
559 | for (i = 0; i < NUM_RTX_CODE; i++) | |
560 | { | |
561 | copy = xstrdup (GET_RTX_NAME (i)); | |
562 | for (p = copy; *p != 0; p++) | |
563 | *p = TOUPPER (*p); | |
564 | ||
565 | lower_ptr = add_map_value (lower_ptr, i, GET_RTX_NAME (i)); | |
566 | upper_ptr = add_map_value (upper_ptr, i, copy); | |
567 | } | |
568 | } | |
875d8740 | 569 | \f |
570 | /* Provide a version of a function to read a long long if the system does | |
571 | not provide one. */ | |
572 | #if HOST_BITS_PER_WIDE_INT > HOST_BITS_PER_LONG && !defined(HAVE_ATOLL) && !defined(HAVE_ATOQ) | |
3ad4992f | 573 | HOST_WIDE_INT atoll (const char *); |
a92a1bb2 | 574 | |
875d8740 | 575 | HOST_WIDE_INT |
3ad4992f | 576 | atoll (const char *p) |
875d8740 | 577 | { |
578 | int neg = 0; | |
579 | HOST_WIDE_INT tmp_wide; | |
580 | ||
337d789b | 581 | while (ISSPACE (*p)) |
875d8740 | 582 | p++; |
583 | if (*p == '-') | |
584 | neg = 1, p++; | |
585 | else if (*p == '+') | |
586 | p++; | |
587 | ||
588 | tmp_wide = 0; | |
337d789b | 589 | while (ISDIGIT (*p)) |
875d8740 | 590 | { |
591 | HOST_WIDE_INT new_wide = tmp_wide*10 + (*p - '0'); | |
592 | if (new_wide < tmp_wide) | |
593 | { | |
594 | /* Return INT_MAX equiv on overflow. */ | |
33181afc | 595 | tmp_wide = (~(unsigned HOST_WIDE_INT) 0) >> 1; |
875d8740 | 596 | break; |
597 | } | |
598 | tmp_wide = new_wide; | |
599 | p++; | |
600 | } | |
601 | ||
602 | if (neg) | |
603 | tmp_wide = -tmp_wide; | |
604 | return tmp_wide; | |
605 | } | |
606 | #endif | |
af908c02 | 607 | \f |
220dcf2f | 608 | /* Process a define_conditions directive, starting with the optional |
609 | space after the "define_conditions". The directive looks like this: | |
af908c02 | 610 | |
611 | (define_conditions [ | |
612 | (number "string") | |
613 | (number "string") | |
614 | ... | |
615 | ]) | |
616 | ||
617 | It's not intended to appear in machine descriptions. It is | |
618 | generated by (the program generated by) genconditions.c, and | |
619 | slipped in at the beginning of the sequence of MD files read by | |
620 | most of the other generators. */ | |
621 | static void | |
220dcf2f | 622 | read_conditions (void) |
af908c02 | 623 | { |
624 | int c; | |
625 | ||
b3453c30 | 626 | c = read_skip_spaces (); |
af908c02 | 627 | if (c != '[') |
b3453c30 | 628 | fatal_expected_char ('[', c); |
af908c02 | 629 | |
b3453c30 | 630 | while ( (c = read_skip_spaces ()) != ']') |
af908c02 | 631 | { |
220dcf2f | 632 | struct md_name name; |
af908c02 | 633 | char *expr; |
634 | int value; | |
635 | ||
636 | if (c != '(') | |
b3453c30 | 637 | fatal_expected_char ('(', c); |
af908c02 | 638 | |
220dcf2f | 639 | read_name (&name); |
640 | validate_const_int (name.string); | |
641 | value = atoi (name.string); | |
af908c02 | 642 | |
b3453c30 | 643 | c = read_skip_spaces (); |
af908c02 | 644 | if (c != '"') |
b3453c30 | 645 | fatal_expected_char ('"', c); |
646 | expr = read_quoted_string (); | |
af908c02 | 647 | |
b3453c30 | 648 | c = read_skip_spaces (); |
af908c02 | 649 | if (c != ')') |
b3453c30 | 650 | fatal_expected_char (')', c); |
af908c02 | 651 | |
652 | add_c_test (expr, value); | |
653 | } | |
af908c02 | 654 | } |
875d8740 | 655 | |
bd7c2be3 | 656 | static void |
b3453c30 | 657 | validate_const_int (const char *string) |
bd7c2be3 | 658 | { |
659 | const char *cp; | |
660 | int valid = 1; | |
661 | ||
662 | cp = string; | |
337d789b | 663 | while (*cp && ISSPACE (*cp)) |
bd7c2be3 | 664 | cp++; |
665 | if (*cp == '-' || *cp == '+') | |
666 | cp++; | |
667 | if (*cp == 0) | |
668 | valid = 0; | |
669 | for (; *cp; cp++) | |
670 | if (! ISDIGIT (*cp)) | |
671 | valid = 0; | |
672 | if (!valid) | |
b3453c30 | 673 | fatal_with_file_and_line ("invalid decimal constant \"%s\"\n", string); |
bd7c2be3 | 674 | } |
675 | ||
f5d566ff | 676 | /* Record that PTR uses iterator ITERATOR. */ |
4a293229 | 677 | |
f5d566ff | 678 | static void |
679 | record_iterator_use (struct mapping *iterator, void *ptr) | |
680 | { | |
e82e4eb5 | 681 | struct iterator_use iuse = {iterator, ptr}; |
f1f41a6c | 682 | iterator_uses.safe_push (iuse); |
f5d566ff | 683 | } |
684 | ||
685 | /* Record that PTR uses attribute VALUE, which must match a built-in | |
686 | value from group GROUP. */ | |
687 | ||
688 | static void | |
689 | record_attribute_use (struct iterator_group *group, void *ptr, | |
690 | const char *value) | |
691 | { | |
e82e4eb5 | 692 | struct attribute_use ause = {group, value, ptr}; |
f1f41a6c | 693 | attribute_uses.safe_push (ause); |
f5d566ff | 694 | } |
695 | ||
696 | /* Interpret NAME as either a built-in value, iterator or attribute | |
697 | for group GROUP. PTR is the value to pass to GROUP's apply_iterator | |
698 | callback. */ | |
699 | ||
700 | static void | |
701 | record_potential_iterator_use (struct iterator_group *group, void *ptr, | |
702 | const char *name) | |
4a293229 | 703 | { |
704 | struct mapping *m; | |
f5d566ff | 705 | size_t len; |
4a293229 | 706 | |
f5d566ff | 707 | len = strlen (name); |
708 | if (name[0] == '<' && name[len - 1] == '>') | |
709 | { | |
710 | /* Copy the attribute string into permanent storage, without the | |
711 | angle brackets around it. */ | |
712 | obstack_grow0 (&string_obstack, name + 1, len - 2); | |
713 | record_attribute_use (group, ptr, XOBFINISH (&string_obstack, char *)); | |
714 | } | |
715 | else | |
716 | { | |
717 | m = (struct mapping *) htab_find (group->iterators, &name); | |
718 | if (m != 0) | |
719 | record_iterator_use (m, ptr); | |
720 | else | |
721 | group->apply_iterator (ptr, group->find_builtin (name)); | |
722 | } | |
4a293229 | 723 | } |
724 | ||
725 | /* Finish reading a declaration of the form: | |
726 | ||
727 | (define... <name> [<value1> ... <valuen>]) | |
728 | ||
b3453c30 | 729 | from the MD file, where each <valuei> is either a bare symbol name or a |
4a293229 | 730 | "(<name> <string>)" pair. The "(define..." part has already been read. |
731 | ||
732 | Represent the declaration as a "mapping" structure; add it to TABLE | |
733 | (which belongs to GROUP) and return it. */ | |
734 | ||
735 | static struct mapping * | |
b3453c30 | 736 | read_mapping (struct iterator_group *group, htab_t table) |
4a293229 | 737 | { |
220dcf2f | 738 | struct md_name name; |
4a293229 | 739 | struct mapping *m; |
740 | struct map_value **end_ptr; | |
741 | const char *string; | |
742 | int number, c; | |
743 | ||
744 | /* Read the mapping name and create a structure for it. */ | |
220dcf2f | 745 | read_name (&name); |
746 | m = add_mapping (group, table, name.string); | |
4a293229 | 747 | |
b3453c30 | 748 | c = read_skip_spaces (); |
4a293229 | 749 | if (c != '[') |
b3453c30 | 750 | fatal_expected_char ('[', c); |
4a293229 | 751 | |
752 | /* Read each value. */ | |
753 | end_ptr = &m->values; | |
b3453c30 | 754 | c = read_skip_spaces (); |
4a293229 | 755 | do |
756 | { | |
757 | if (c != '(') | |
758 | { | |
759 | /* A bare symbol name that is implicitly paired to an | |
760 | empty string. */ | |
b3453c30 | 761 | unread_char (c); |
220dcf2f | 762 | read_name (&name); |
4a293229 | 763 | string = ""; |
764 | } | |
765 | else | |
766 | { | |
767 | /* A "(name string)" pair. */ | |
220dcf2f | 768 | read_name (&name); |
b3453c30 | 769 | string = read_string (false); |
770 | c = read_skip_spaces (); | |
4a293229 | 771 | if (c != ')') |
b3453c30 | 772 | fatal_expected_char (')', c); |
4a293229 | 773 | } |
220dcf2f | 774 | number = group->find_builtin (name.string); |
4a293229 | 775 | end_ptr = add_map_value (end_ptr, number, string); |
b3453c30 | 776 | c = read_skip_spaces (); |
4a293229 | 777 | } |
778 | while (c != ']'); | |
779 | ||
4a293229 | 780 | return m; |
781 | } | |
782 | ||
fd781bb2 | 783 | /* Check newly-created code iterator ITERATOR to see whether every code has the |
f5d566ff | 784 | same format. */ |
4a293229 | 785 | |
786 | static void | |
b3453c30 | 787 | check_code_iterator (struct mapping *iterator) |
4a293229 | 788 | { |
789 | struct map_value *v; | |
790 | enum rtx_code bellwether; | |
791 | ||
fd781bb2 | 792 | bellwether = (enum rtx_code) iterator->values->number; |
793 | for (v = iterator->values->next; v != 0; v = v->next) | |
4a293229 | 794 | if (strcmp (GET_RTX_FORMAT (bellwether), GET_RTX_FORMAT (v->number)) != 0) |
b3453c30 | 795 | fatal_with_file_and_line ("code iterator `%s' combines " |
fd781bb2 | 796 | "different rtx formats", iterator->name); |
4a293229 | 797 | } |
798 | ||
77ba95d0 | 799 | /* Read an rtx-related declaration from the MD file, given that it |
800 | starts with directive name RTX_NAME. Return true if it expands to | |
801 | one or more rtxes (as defined by rtx.def). When returning true, | |
802 | store the list of rtxes as an EXPR_LIST in *X. */ | |
875d8740 | 803 | |
fea520eb | 804 | bool |
77ba95d0 | 805 | read_rtx (const char *rtx_name, rtx *x) |
875d8740 | 806 | { |
77ba95d0 | 807 | static rtx queue_head; |
4a293229 | 808 | |
809 | /* Do one-time initialization. */ | |
810 | if (queue_head == 0) | |
811 | { | |
fd781bb2 | 812 | initialize_iterators (); |
4a293229 | 813 | queue_head = rtx_alloc (EXPR_LIST); |
814 | } | |
815 | ||
77ba95d0 | 816 | /* Handle various rtx-related declarations that aren't themselves |
817 | encoded as rtxes. */ | |
818 | if (strcmp (rtx_name, "define_conditions") == 0) | |
4a293229 | 819 | { |
77ba95d0 | 820 | read_conditions (); |
821 | return false; | |
4a293229 | 822 | } |
77ba95d0 | 823 | if (strcmp (rtx_name, "define_mode_attr") == 0) |
824 | { | |
825 | read_mapping (&modes, modes.attrs); | |
826 | return false; | |
827 | } | |
828 | if (strcmp (rtx_name, "define_mode_iterator") == 0) | |
829 | { | |
830 | read_mapping (&modes, modes.iterators); | |
831 | return false; | |
832 | } | |
833 | if (strcmp (rtx_name, "define_code_attr") == 0) | |
834 | { | |
835 | read_mapping (&codes, codes.attrs); | |
836 | return false; | |
837 | } | |
838 | if (strcmp (rtx_name, "define_code_iterator") == 0) | |
839 | { | |
840 | check_code_iterator (read_mapping (&codes, codes.iterators)); | |
841 | return false; | |
842 | } | |
65729bd0 | 843 | if (strcmp (rtx_name, "define_int_attr") == 0) |
844 | { | |
845 | read_mapping (&ints, ints.attrs); | |
846 | return false; | |
847 | } | |
848 | if (strcmp (rtx_name, "define_int_iterator") == 0) | |
849 | { | |
850 | read_mapping (&ints, ints.iterators); | |
851 | return false; | |
852 | } | |
77ba95d0 | 853 | |
f5d566ff | 854 | apply_iterators (read_rtx_code (rtx_name), &queue_head); |
f1f41a6c | 855 | iterator_uses.truncate (0); |
856 | attribute_uses.truncate (0); | |
4a293229 | 857 | |
77ba95d0 | 858 | *x = queue_head; |
fea520eb | 859 | return true; |
4a293229 | 860 | } |
861 | ||
77ba95d0 | 862 | /* Subroutine of read_rtx and read_nested_rtx. CODE_NAME is the name of |
863 | either an rtx code or a code iterator. Parse the rest of the rtx and | |
f5d566ff | 864 | return it. */ |
4a293229 | 865 | |
866 | static rtx | |
f5d566ff | 867 | read_rtx_code (const char *code_name) |
4a293229 | 868 | { |
869 | int i; | |
f5d566ff | 870 | RTX_CODE code; |
871 | struct mapping *iterator; | |
19cb6b50 | 872 | const char *format_ptr; |
220dcf2f | 873 | struct md_name name; |
875d8740 | 874 | rtx return_rtx; |
19cb6b50 | 875 | int c; |
875d8740 | 876 | HOST_WIDE_INT tmp_wide; |
877 | ||
875d8740 | 878 | /* Linked list structure for making RTXs: */ |
879 | struct rtx_list | |
880 | { | |
881 | struct rtx_list *next; | |
882 | rtx value; /* Value of this node. */ | |
883 | }; | |
884 | ||
f5d566ff | 885 | /* If this code is an iterator, build the rtx using the iterator's |
886 | first value. */ | |
887 | iterator = (struct mapping *) htab_find (codes.iterators, &code_name); | |
888 | if (iterator != 0) | |
889 | code = (enum rtx_code) iterator->values->number; | |
890 | else | |
891 | code = (enum rtx_code) codes.find_builtin (code_name); | |
875d8740 | 892 | |
893 | /* If we end up with an insn expression then we free this space below. */ | |
f5d566ff | 894 | return_rtx = rtx_alloc (code); |
895 | format_ptr = GET_RTX_FORMAT (code); | |
896 | PUT_CODE (return_rtx, code); | |
897 | ||
898 | if (iterator) | |
899 | record_iterator_use (iterator, return_rtx); | |
875d8740 | 900 | |
901 | /* If what follows is `: mode ', read it and | |
902 | store the mode in the rtx. */ | |
903 | ||
b3453c30 | 904 | i = read_skip_spaces (); |
875d8740 | 905 | if (i == ':') |
906 | { | |
220dcf2f | 907 | read_name (&name); |
f5d566ff | 908 | record_potential_iterator_use (&modes, return_rtx, name.string); |
875d8740 | 909 | } |
910 | else | |
b3453c30 | 911 | unread_char (i); |
875d8740 | 912 | |
6f7111d2 | 913 | for (i = 0; format_ptr[i] != 0; i++) |
914 | switch (format_ptr[i]) | |
875d8740 | 915 | { |
916 | /* 0 means a field for internal use only. | |
917 | Don't expect it to be present in the input. */ | |
918 | case '0': | |
919 | break; | |
920 | ||
921 | case 'e': | |
922 | case 'u': | |
f5d566ff | 923 | XEXP (return_rtx, i) = read_nested_rtx (); |
875d8740 | 924 | break; |
925 | ||
926 | case 'V': | |
927 | /* 'V' is an optional vector: if a closeparen follows, | |
928 | just store NULL for this element. */ | |
b3453c30 | 929 | c = read_skip_spaces (); |
930 | unread_char (c); | |
875d8740 | 931 | if (c == ')') |
932 | { | |
933 | XVEC (return_rtx, i) = 0; | |
934 | break; | |
2617fe26 | 935 | } |
875d8740 | 936 | /* Now process the vector. */ |
937 | ||
938 | case 'E': | |
939 | { | |
940 | /* Obstack to store scratch vector in. */ | |
941 | struct obstack vector_stack; | |
942 | int list_counter = 0; | |
943 | rtvec return_vec = NULL_RTVEC; | |
944 | ||
b3453c30 | 945 | c = read_skip_spaces (); |
875d8740 | 946 | if (c != '[') |
b3453c30 | 947 | fatal_expected_char ('[', c); |
875d8740 | 948 | |
aab2cf92 | 949 | /* Add expressions to a list, while keeping a count. */ |
875d8740 | 950 | obstack_init (&vector_stack); |
b3453c30 | 951 | while ((c = read_skip_spaces ()) && c != ']') |
875d8740 | 952 | { |
ed99630c | 953 | if (c == EOF) |
b3453c30 | 954 | fatal_expected_char (']', c); |
955 | unread_char (c); | |
875d8740 | 956 | list_counter++; |
f5d566ff | 957 | obstack_ptr_grow (&vector_stack, read_nested_rtx ()); |
875d8740 | 958 | } |
959 | if (list_counter > 0) | |
960 | { | |
961 | return_vec = rtvec_alloc (list_counter); | |
962 | memcpy (&return_vec->elem[0], obstack_finish (&vector_stack), | |
963 | list_counter * sizeof (rtx)); | |
964 | } | |
fb210ebf | 965 | else if (format_ptr[i] == 'E') |
b3453c30 | 966 | fatal_with_file_and_line ("vector must have at least one element"); |
875d8740 | 967 | XVEC (return_rtx, i) = return_vec; |
968 | obstack_free (&vector_stack, NULL); | |
969 | /* close bracket gotten */ | |
970 | } | |
971 | break; | |
972 | ||
973 | case 'S': | |
aa4c562d | 974 | case 'T': |
875d8740 | 975 | case 's': |
976 | { | |
977 | char *stringbuf; | |
3a7ca9df | 978 | int star_if_braced; |
979 | ||
b3453c30 | 980 | c = read_skip_spaces (); |
981 | unread_char (c); | |
3a7ca9df | 982 | if (c == ')') |
983 | { | |
984 | /* 'S' fields are optional and should be NULL if no string | |
985 | was given. Also allow normal 's' and 'T' strings to be | |
986 | omitted, treating them in the same way as empty strings. */ | |
6f7111d2 | 987 | XSTR (return_rtx, i) = (format_ptr[i] == 'S' ? NULL : ""); |
3a7ca9df | 988 | break; |
989 | } | |
875d8740 | 990 | |
991 | /* The output template slot of a DEFINE_INSN, | |
992 | DEFINE_INSN_AND_SPLIT, or DEFINE_PEEPHOLE automatically | |
993 | gets a star inserted as its first character, if it is | |
994 | written with a brace block instead of a string constant. */ | |
6f7111d2 | 995 | star_if_braced = (format_ptr[i] == 'T'); |
2617fe26 | 996 | |
b3453c30 | 997 | stringbuf = read_string (star_if_braced); |
875d8740 | 998 | |
999 | /* For insn patterns, we want to provide a default name | |
1000 | based on the file and line, like "*foo.md:12", if the | |
1001 | given name is blank. These are only for define_insn and | |
1002 | define_insn_and_split, to aid debugging. */ | |
1003 | if (*stringbuf == '\0' | |
1004 | && i == 0 | |
1005 | && (GET_CODE (return_rtx) == DEFINE_INSN | |
1006 | || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT)) | |
1007 | { | |
1008 | char line_name[20]; | |
77c2564f | 1009 | const char *fn = (read_md_filename ? read_md_filename : "rtx"); |
875d8740 | 1010 | const char *slash; |
1011 | for (slash = fn; *slash; slash ++) | |
1012 | if (*slash == '/' || *slash == '\\' || *slash == ':') | |
1013 | fn = slash + 1; | |
a50f2245 | 1014 | obstack_1grow (&string_obstack, '*'); |
1015 | obstack_grow (&string_obstack, fn, strlen (fn)); | |
77c2564f | 1016 | sprintf (line_name, ":%d", read_md_lineno); |
a50f2245 | 1017 | obstack_grow (&string_obstack, line_name, strlen (line_name)+1); |
4fac984f | 1018 | stringbuf = XOBFINISH (&string_obstack, char *); |
875d8740 | 1019 | } |
1020 | ||
aa4c562d | 1021 | if (star_if_braced) |
1022 | XTMPL (return_rtx, i) = stringbuf; | |
1023 | else | |
1024 | XSTR (return_rtx, i) = stringbuf; | |
875d8740 | 1025 | } |
1026 | break; | |
1027 | ||
1028 | case 'w': | |
220dcf2f | 1029 | read_name (&name); |
1030 | validate_const_int (name.string); | |
875d8740 | 1031 | #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT |
220dcf2f | 1032 | tmp_wide = atoi (name.string); |
875d8740 | 1033 | #else |
1034 | #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG | |
220dcf2f | 1035 | tmp_wide = atol (name.string); |
875d8740 | 1036 | #else |
1037 | /* Prefer atoll over atoq, since the former is in the ISO C99 standard. | |
1038 | But prefer not to use our hand-rolled function above either. */ | |
1039 | #if defined(HAVE_ATOLL) || !defined(HAVE_ATOQ) | |
220dcf2f | 1040 | tmp_wide = atoll (name.string); |
875d8740 | 1041 | #else |
220dcf2f | 1042 | tmp_wide = atoq (name.string); |
875d8740 | 1043 | #endif |
1044 | #endif | |
1045 | #endif | |
1046 | XWINT (return_rtx, i) = tmp_wide; | |
1047 | break; | |
1048 | ||
1049 | case 'i': | |
1050 | case 'n': | |
65729bd0 | 1051 | /* Can be an iterator or an integer constant. */ |
220dcf2f | 1052 | read_name (&name); |
65729bd0 | 1053 | record_potential_iterator_use (&ints, &XINT (return_rtx, i), |
1054 | name.string); | |
875d8740 | 1055 | break; |
1056 | ||
1057 | default: | |
1fa3a8f6 | 1058 | gcc_unreachable (); |
875d8740 | 1059 | } |
1060 | ||
77ba95d0 | 1061 | c = read_skip_spaces (); |
1062 | /* Syntactic sugar for AND and IOR, allowing Lisp-like | |
1063 | arbitrary number of arguments for them. */ | |
1064 | if (c == '(' | |
1065 | && (GET_CODE (return_rtx) == AND | |
1066 | || GET_CODE (return_rtx) == IOR)) | |
f5d566ff | 1067 | return read_rtx_variadic (return_rtx); |
77ba95d0 | 1068 | |
1069 | unread_char (c); | |
1070 | return return_rtx; | |
1071 | } | |
1072 | ||
f5d566ff | 1073 | /* Read a nested rtx construct from the MD file and return it. */ |
77ba95d0 | 1074 | |
1075 | static rtx | |
f5d566ff | 1076 | read_nested_rtx (void) |
77ba95d0 | 1077 | { |
1078 | struct md_name name; | |
1079 | int c; | |
1080 | rtx return_rtx; | |
1081 | ||
1082 | c = read_skip_spaces (); | |
1083 | if (c != '(') | |
1084 | fatal_expected_char ('(', c); | |
1085 | ||
1086 | read_name (&name); | |
1087 | if (strcmp (name.string, "nil") == 0) | |
1088 | return_rtx = NULL; | |
1089 | else | |
f5d566ff | 1090 | return_rtx = read_rtx_code (name.string); |
77ba95d0 | 1091 | |
b3453c30 | 1092 | c = read_skip_spaces (); |
875d8740 | 1093 | if (c != ')') |
77ba95d0 | 1094 | fatal_expected_char (')', c); |
875d8740 | 1095 | |
1096 | return return_rtx; | |
1097 | } | |
6c9ff279 | 1098 | |
1099 | /* Mutually recursive subroutine of read_rtx which reads | |
1100 | (thing x1 x2 x3 ...) and produces RTL as if | |
1101 | (thing x1 (thing x2 (thing x3 ...))) had been written. | |
1102 | When called, FORM is (thing x1 x2), and the file position | |
1103 | is just past the leading parenthesis of x3. Only works | |
1104 | for THINGs which are dyadic expressions, e.g. AND, IOR. */ | |
1105 | static rtx | |
f5d566ff | 1106 | read_rtx_variadic (rtx form) |
6c9ff279 | 1107 | { |
1108 | char c = '('; | |
1109 | rtx p = form, q; | |
1110 | ||
1111 | do | |
1112 | { | |
b3453c30 | 1113 | unread_char (c); |
6c9ff279 | 1114 | |
1115 | q = rtx_alloc (GET_CODE (p)); | |
1116 | PUT_MODE (q, GET_MODE (p)); | |
1117 | ||
1118 | XEXP (q, 0) = XEXP (p, 1); | |
f5d566ff | 1119 | XEXP (q, 1) = read_nested_rtx (); |
48e1416a | 1120 | |
6c9ff279 | 1121 | XEXP (p, 1) = q; |
1122 | p = q; | |
b3453c30 | 1123 | c = read_skip_spaces (); |
6c9ff279 | 1124 | } |
1125 | while (c == '('); | |
77ba95d0 | 1126 | unread_char (c); |
6c9ff279 | 1127 | return form; |
1128 | } |