]>
Commit | Line | Data |
---|---|---|
5e6908ea | 1 | /* RTL reader for GCC. |
23a5b65a | 2 | Copyright (C) 1987-2014 Free Software Foundation, Inc. |
0f40f9f7 | 3 | |
1322177d | 4 | This file is part of GCC. |
0f40f9f7 | 5 | |
1322177d LB |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free | |
9dcd6f09 | 8 | Software Foundation; either version 3, or (at your option) any later |
1322177d | 9 | version. |
0f40f9f7 | 10 | |
1322177d LB |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | for more details. | |
0f40f9f7 ZW |
15 | |
16 | You should have received a copy of the GNU General Public License | |
9dcd6f09 NC |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ | |
0f40f9f7 | 19 | |
4977bab6 | 20 | #include "bconfig.h" |
f51a38b9 | 21 | |
3abcb3a7 | 22 | /* Disable rtl checking; it conflicts with the iterator handling. */ |
f51a38b9 RS |
23 | #undef ENABLE_RTL_CHECKING |
24 | ||
0f40f9f7 | 25 | #include "system.h" |
4977bab6 ZW |
26 | #include "coretypes.h" |
27 | #include "tm.h" | |
0f40f9f7 ZW |
28 | #include "rtl.h" |
29 | #include "obstack.h" | |
30 | #include "hashtab.h" | |
10692477 | 31 | #include "read-md.h" |
1c7352cd | 32 | #include "gensupport.h" |
0f40f9f7 | 33 | |
032e8348 RS |
34 | /* One element in a singly-linked list of (integer, string) pairs. */ |
35 | struct map_value { | |
36 | struct map_value *next; | |
37 | int number; | |
38 | const char *string; | |
39 | }; | |
40 | ||
3abcb3a7 | 41 | /* Maps an iterator or attribute name to a list of (integer, string) pairs. |
b78fd164 | 42 | The integers are iterator values; the strings are either C conditions |
032e8348 RS |
43 | or attribute values. */ |
44 | struct mapping { | |
3abcb3a7 | 45 | /* The name of the iterator or attribute. */ |
032e8348 RS |
46 | const char *name; |
47 | ||
3abcb3a7 HPN |
48 | /* The group (modes or codes) to which the iterator or attribute belongs. */ |
49 | struct iterator_group *group; | |
032e8348 | 50 | |
032e8348 RS |
51 | /* The list of (integer, string) pairs. */ |
52 | struct map_value *values; | |
b78fd164 RS |
53 | |
54 | /* For iterators, records the current value of the iterator. */ | |
55 | struct map_value *current_value; | |
032e8348 RS |
56 | }; |
57 | ||
b78fd164 RS |
58 | /* Vector definitions for the above. */ |
59 | typedef struct mapping *mapping_ptr; | |
b78fd164 RS |
60 | |
61 | /* A structure for abstracting the common parts of iterators. */ | |
3abcb3a7 | 62 | struct iterator_group { |
b78fd164 RS |
63 | /* Tables of "mapping" structures, one for attributes and one for |
64 | iterators. */ | |
3abcb3a7 | 65 | htab_t attrs, iterators; |
032e8348 | 66 | |
b78fd164 | 67 | /* Treat the given string as the name of a standard mode, etc., and |
c5e88b39 RS |
68 | return its integer value. */ |
69 | int (*find_builtin) (const char *); | |
032e8348 | 70 | |
b78fd164 RS |
71 | /* Make the given pointer use the given iterator value. */ |
72 | void (*apply_iterator) (void *, int); | |
73 | }; | |
032e8348 | 74 | |
b78fd164 RS |
75 | /* Records one use of an iterator. */ |
76 | struct iterator_use { | |
77 | /* The iterator itself. */ | |
78 | struct mapping *iterator; | |
79 | ||
80 | /* The location of the use, as passed to the apply_iterator callback. */ | |
81 | void *ptr; | |
032e8348 RS |
82 | }; |
83 | ||
b78fd164 RS |
84 | /* Vector definitions for the above. */ |
85 | typedef struct iterator_use iterator_use; | |
b78fd164 RS |
86 | |
87 | /* Records one use of an attribute (the "<[iterator:]attribute>" syntax) | |
88 | in a non-string rtx field. */ | |
89 | struct attribute_use { | |
90 | /* The group that describes the use site. */ | |
91 | struct iterator_group *group; | |
92 | ||
93 | /* The name of the attribute, possibly with an "iterator:" prefix. */ | |
94 | const char *value; | |
95 | ||
96 | /* The location of the use, as passed to GROUP's apply_iterator callback. */ | |
97 | void *ptr; | |
f30990b2 ILT |
98 | }; |
99 | ||
b78fd164 RS |
100 | /* Vector definitions for the above. */ |
101 | typedef struct attribute_use attribute_use; | |
b78fd164 | 102 | |
477c104e MK |
103 | /* This struct is used to link subst_attr named ATTR_NAME with |
104 | corresponding define_subst named ITER_NAME. */ | |
105 | struct subst_attr_to_iter_mapping | |
106 | { | |
107 | char *attr_name; | |
108 | char *iter_name; | |
109 | }; | |
110 | ||
111 | /* Hash-table to store links between subst-attributes and | |
112 | define_substs. */ | |
113 | htab_t subst_attr_to_iter_map = NULL; | |
114 | /* This global stores name of subst-iterator which is currently being | |
115 | processed. */ | |
116 | const char *current_iterator_name; | |
117 | ||
c5e88b39 | 118 | static void validate_const_int (const char *); |
b78fd164 RS |
119 | static rtx read_rtx_code (const char *); |
120 | static rtx read_nested_rtx (void); | |
121 | static rtx read_rtx_variadic (rtx); | |
032e8348 | 122 | |
3abcb3a7 | 123 | /* The mode and code iterator structures. */ |
477c104e | 124 | static struct iterator_group modes, codes, ints, substs; |
032e8348 | 125 | |
b78fd164 | 126 | /* All iterators used in the current rtx. */ |
9771b263 | 127 | static vec<mapping_ptr> current_iterators; |
b78fd164 RS |
128 | |
129 | /* The list of all iterator uses in the current rtx. */ | |
9771b263 | 130 | static vec<iterator_use> iterator_uses; |
b78fd164 RS |
131 | |
132 | /* The list of all attribute uses in the current rtx. */ | |
9771b263 | 133 | static vec<attribute_use> attribute_uses; |
0f40f9f7 | 134 | |
3abcb3a7 | 135 | /* Implementations of the iterator_group callbacks for modes. */ |
032e8348 RS |
136 | |
137 | static int | |
c5e88b39 | 138 | find_mode (const char *name) |
032e8348 RS |
139 | { |
140 | int i; | |
141 | ||
142 | for (i = 0; i < NUM_MACHINE_MODES; i++) | |
143 | if (strcmp (GET_MODE_NAME (i), name) == 0) | |
144 | return i; | |
145 | ||
c5e88b39 | 146 | fatal_with_file_and_line ("unknown mode `%s'", name); |
032e8348 RS |
147 | } |
148 | ||
032e8348 | 149 | static void |
b78fd164 | 150 | apply_mode_iterator (void *loc, int mode) |
032e8348 | 151 | { |
b78fd164 | 152 | PUT_MODE ((rtx) loc, (enum machine_mode) mode); |
032e8348 RS |
153 | } |
154 | ||
3abcb3a7 | 155 | /* Implementations of the iterator_group callbacks for codes. */ |
032e8348 RS |
156 | |
157 | static int | |
c5e88b39 | 158 | find_code (const char *name) |
032e8348 RS |
159 | { |
160 | int i; | |
161 | ||
162 | for (i = 0; i < NUM_RTX_CODE; i++) | |
163 | if (strcmp (GET_RTX_NAME (i), name) == 0) | |
164 | return i; | |
165 | ||
c5e88b39 | 166 | fatal_with_file_and_line ("unknown rtx code `%s'", name); |
032e8348 RS |
167 | } |
168 | ||
032e8348 | 169 | static void |
b78fd164 | 170 | apply_code_iterator (void *loc, int code) |
032e8348 | 171 | { |
b78fd164 | 172 | PUT_CODE ((rtx) loc, (enum rtx_code) code); |
032e8348 RS |
173 | } |
174 | ||
57a4717b TB |
175 | /* Implementations of the iterator_group callbacks for ints. */ |
176 | ||
177 | /* Since GCC does not construct a table of valid constants, | |
178 | we have to accept any int as valid. No cross-checking can | |
179 | be done. */ | |
180 | ||
181 | static int | |
182 | find_int (const char *name) | |
183 | { | |
184 | validate_const_int (name); | |
185 | return atoi (name); | |
186 | } | |
187 | ||
188 | static void | |
189 | apply_int_iterator (void *loc, int value) | |
190 | { | |
191 | *(int *)loc = value; | |
192 | } | |
193 | ||
477c104e MK |
194 | /* This routine adds attribute or does nothing depending on VALUE. When |
195 | VALUE is 1, it does nothing - the first duplicate of original | |
196 | template is kept untouched when it's subjected to a define_subst. | |
197 | When VALUE isn't 1, the routine modifies RTL-template LOC, adding | |
198 | attribute, named exactly as define_subst, which later will be | |
199 | applied. If such attribute has already been added, then no the | |
200 | routine has no effect. */ | |
201 | static void | |
202 | apply_subst_iterator (void *loc, int value) | |
203 | { | |
204 | rtx rt = (rtx)loc; | |
205 | rtx new_attr; | |
206 | rtvec attrs_vec, new_attrs_vec; | |
207 | int i; | |
208 | if (value == 1) | |
209 | return; | |
210 | gcc_assert (GET_CODE (rt) == DEFINE_INSN | |
211 | || GET_CODE (rt) == DEFINE_EXPAND); | |
212 | ||
213 | attrs_vec = XVEC (rt, 4); | |
214 | ||
215 | /* If we've already added attribute 'current_iterator_name', then we | |
216 | have nothing to do now. */ | |
217 | if (attrs_vec) | |
218 | { | |
219 | for (i = 0; i < GET_NUM_ELEM (attrs_vec); i++) | |
220 | { | |
221 | if (strcmp (XSTR (attrs_vec->elem[i], 0), current_iterator_name) == 0) | |
222 | return; | |
223 | } | |
224 | } | |
225 | ||
226 | /* Add attribute with subst name - it serves as a mark for | |
227 | define_subst which later would be applied to this pattern. */ | |
228 | new_attr = rtx_alloc (SET_ATTR); | |
229 | PUT_CODE (new_attr, SET_ATTR); | |
230 | XSTR (new_attr, 0) = xstrdup (current_iterator_name); | |
231 | XSTR (new_attr, 1) = xstrdup ("yes"); | |
232 | ||
233 | if (!attrs_vec) | |
234 | { | |
235 | new_attrs_vec = rtvec_alloc (1); | |
236 | new_attrs_vec->elem[0] = new_attr; | |
237 | } | |
238 | else | |
239 | { | |
240 | new_attrs_vec = rtvec_alloc (GET_NUM_ELEM (attrs_vec) + 1); | |
241 | memcpy (&new_attrs_vec->elem[0], &attrs_vec->elem[0], | |
242 | GET_NUM_ELEM (attrs_vec) * sizeof (rtx)); | |
243 | new_attrs_vec->elem[GET_NUM_ELEM (attrs_vec)] = new_attr; | |
244 | } | |
245 | XVEC (rt, 4) = new_attrs_vec; | |
246 | } | |
247 | ||
248 | /* Map subst-attribute ATTR to subst iterator ITER. */ | |
249 | ||
250 | static void | |
251 | bind_subst_iter_and_attr (const char *iter, const char *attr) | |
252 | { | |
253 | struct subst_attr_to_iter_mapping *value; | |
254 | void **slot; | |
255 | if (!subst_attr_to_iter_map) | |
256 | subst_attr_to_iter_map = | |
257 | htab_create (1, leading_string_hash, leading_string_eq_p, 0); | |
258 | value = XNEW (struct subst_attr_to_iter_mapping); | |
259 | value->attr_name = xstrdup (attr); | |
260 | value->iter_name = xstrdup (iter); | |
261 | slot = htab_find_slot (subst_attr_to_iter_map, value, INSERT); | |
262 | *slot = value; | |
263 | } | |
264 | ||
265 | /* Return name of a subst-iterator, corresponding to subst-attribute ATTR. */ | |
266 | ||
267 | static char* | |
268 | find_subst_iter_by_attr (const char *attr) | |
269 | { | |
270 | char *iter_name = NULL; | |
271 | struct subst_attr_to_iter_mapping *value; | |
272 | value = (struct subst_attr_to_iter_mapping*) | |
273 | htab_find (subst_attr_to_iter_map, &attr); | |
274 | if (value) | |
275 | iter_name = value->iter_name; | |
276 | return iter_name; | |
277 | } | |
278 | ||
b78fd164 RS |
279 | /* Map attribute string P to its current value. Return null if the attribute |
280 | isn't known. */ | |
f30990b2 ILT |
281 | |
282 | static struct map_value * | |
b78fd164 | 283 | map_attr_string (const char *p) |
f30990b2 ILT |
284 | { |
285 | const char *attr; | |
b78fd164 RS |
286 | struct mapping *iterator; |
287 | unsigned int i; | |
f30990b2 ILT |
288 | struct mapping *m; |
289 | struct map_value *v; | |
b78fd164 | 290 | int iterator_name_len; |
f30990b2 | 291 | |
b78fd164 RS |
292 | /* Peel off any "iterator:" prefix. Set ATTR to the start of the |
293 | attribute name. */ | |
f30990b2 ILT |
294 | attr = strchr (p, ':'); |
295 | if (attr == 0) | |
b78fd164 RS |
296 | { |
297 | iterator_name_len = -1; | |
298 | attr = p; | |
299 | } | |
f30990b2 ILT |
300 | else |
301 | { | |
b78fd164 | 302 | iterator_name_len = attr - p; |
f30990b2 ILT |
303 | attr++; |
304 | } | |
305 | ||
9771b263 | 306 | FOR_EACH_VEC_ELT (current_iterators, i, iterator) |
f30990b2 | 307 | { |
b78fd164 RS |
308 | /* If an iterator name was specified, check that it matches. */ |
309 | if (iterator_name_len >= 0 | |
310 | && (strncmp (p, iterator->name, iterator_name_len) != 0 | |
311 | || iterator->name[iterator_name_len] != 0)) | |
312 | continue; | |
f30990b2 | 313 | |
b78fd164 RS |
314 | /* Find the attribute specification. */ |
315 | m = (struct mapping *) htab_find (iterator->group->attrs, &attr); | |
316 | if (m) | |
477c104e MK |
317 | { |
318 | /* In contrast to code/mode/int iterators, attributes of subst | |
319 | iterators are linked to one specific subst-iterator. So, if | |
320 | we are dealing with subst-iterator, we should check if it's | |
321 | the one which linked with the given attribute. */ | |
322 | if (iterator->group == &substs) | |
323 | { | |
324 | char *iter_name = find_subst_iter_by_attr (attr); | |
325 | if (strcmp (iter_name, iterator->name) != 0) | |
326 | continue; | |
327 | } | |
328 | /* Find the attribute value associated with the current | |
329 | iterator value. */ | |
330 | for (v = m->values; v; v = v->next) | |
331 | if (v->number == iterator->current_value->number) | |
332 | return v; | |
333 | } | |
f30990b2 | 334 | } |
b78fd164 | 335 | return NULL; |
f30990b2 ILT |
336 | } |
337 | ||
b78fd164 RS |
338 | /* Apply the current iterator values to STRING. Return the new string |
339 | if any changes were needed, otherwise return STRING itself. */ | |
032e8348 RS |
340 | |
341 | static const char * | |
b78fd164 | 342 | apply_iterator_to_string (const char *string) |
032e8348 | 343 | { |
f30990b2 | 344 | char *base, *copy, *p, *start, *end; |
032e8348 RS |
345 | struct map_value *v; |
346 | ||
347 | if (string == 0) | |
348 | return string; | |
349 | ||
350 | base = p = copy = ASTRDUP (string); | |
b4f69040 | 351 | while ((start = strchr (p, '<')) && (end = strchr (start, '>'))) |
032e8348 RS |
352 | { |
353 | p = start + 1; | |
354 | ||
032e8348 | 355 | *end = 0; |
b78fd164 | 356 | v = map_attr_string (p); |
032e8348 | 357 | *end = '>'; |
032e8348 RS |
358 | if (v == 0) |
359 | continue; | |
360 | ||
361 | /* Add everything between the last copied byte and the '<', | |
362 | then add in the attribute value. */ | |
363 | obstack_grow (&string_obstack, base, start - base); | |
364 | obstack_grow (&string_obstack, v->string, strlen (v->string)); | |
365 | base = end + 1; | |
366 | } | |
367 | if (base != copy) | |
368 | { | |
369 | obstack_grow (&string_obstack, base, strlen (base) + 1); | |
7973fd2a | 370 | copy = XOBFINISH (&string_obstack, char *); |
d2a3ce4e | 371 | copy_md_ptr_loc (copy, string); |
7445392c | 372 | return copy; |
032e8348 RS |
373 | } |
374 | return string; | |
375 | } | |
376 | ||
b78fd164 RS |
377 | /* Return a deep copy of X, substituting the current iterator |
378 | values into any strings. */ | |
032e8348 RS |
379 | |
380 | static rtx | |
b78fd164 | 381 | copy_rtx_for_iterators (rtx original) |
032e8348 | 382 | { |
c0602ab8 | 383 | const char *format_ptr, *p; |
032e8348 RS |
384 | int i, j; |
385 | rtx x; | |
032e8348 RS |
386 | |
387 | if (original == 0) | |
388 | return original; | |
389 | ||
390 | /* Create a shallow copy of ORIGINAL. */ | |
b78fd164 RS |
391 | x = rtx_alloc (GET_CODE (original)); |
392 | memcpy (x, original, RTX_CODE_SIZE (GET_CODE (original))); | |
f30990b2 | 393 | |
032e8348 | 394 | /* Change each string and recursively change each rtx. */ |
b78fd164 | 395 | format_ptr = GET_RTX_FORMAT (GET_CODE (original)); |
032e8348 RS |
396 | for (i = 0; format_ptr[i] != 0; i++) |
397 | switch (format_ptr[i]) | |
398 | { | |
032e8348 | 399 | case 'T': |
c0602ab8 MZ |
400 | while (XTMPL (x, i) != (p = apply_iterator_to_string (XTMPL (x, i)))) |
401 | XTMPL (x, i) = p; | |
f51a38b9 RS |
402 | break; |
403 | ||
404 | case 'S': | |
032e8348 | 405 | case 's': |
c0602ab8 MZ |
406 | while (XSTR (x, i) != (p = apply_iterator_to_string (XSTR (x, i)))) |
407 | XSTR (x, i) = p; | |
032e8348 RS |
408 | break; |
409 | ||
410 | case 'e': | |
b78fd164 | 411 | XEXP (x, i) = copy_rtx_for_iterators (XEXP (x, i)); |
032e8348 RS |
412 | break; |
413 | ||
414 | case 'V': | |
415 | case 'E': | |
416 | if (XVEC (original, i)) | |
417 | { | |
418 | XVEC (x, i) = rtvec_alloc (XVECLEN (original, i)); | |
419 | for (j = 0; j < XVECLEN (x, i); j++) | |
b78fd164 RS |
420 | XVECEXP (x, i, j) |
421 | = copy_rtx_for_iterators (XVECEXP (original, i, j)); | |
032e8348 RS |
422 | } |
423 | break; | |
424 | ||
425 | default: | |
426 | break; | |
427 | } | |
428 | return x; | |
429 | } | |
430 | ||
032e8348 RS |
431 | /* Return a condition that must satisfy both ORIGINAL and EXTRA. If ORIGINAL |
432 | has the form "&& ..." (as used in define_insn_and_splits), assume that | |
433 | EXTRA is already satisfied. Empty strings are treated like "true". */ | |
434 | ||
435 | static const char * | |
436 | add_condition_to_string (const char *original, const char *extra) | |
437 | { | |
7445392c | 438 | if (original != 0 && original[0] == '&' && original[1] == '&') |
032e8348 | 439 | return original; |
7445392c | 440 | return join_c_conditions (original, extra); |
032e8348 RS |
441 | } |
442 | ||
443 | /* Like add_condition, but applied to all conditions in rtx X. */ | |
444 | ||
445 | static void | |
446 | add_condition_to_rtx (rtx x, const char *extra) | |
447 | { | |
448 | switch (GET_CODE (x)) | |
449 | { | |
450 | case DEFINE_INSN: | |
451 | case DEFINE_EXPAND: | |
477c104e | 452 | case DEFINE_SUBST: |
032e8348 RS |
453 | XSTR (x, 2) = add_condition_to_string (XSTR (x, 2), extra); |
454 | break; | |
455 | ||
456 | case DEFINE_SPLIT: | |
457 | case DEFINE_PEEPHOLE: | |
458 | case DEFINE_PEEPHOLE2: | |
459 | case DEFINE_COND_EXEC: | |
460 | XSTR (x, 1) = add_condition_to_string (XSTR (x, 1), extra); | |
461 | break; | |
462 | ||
463 | case DEFINE_INSN_AND_SPLIT: | |
464 | XSTR (x, 2) = add_condition_to_string (XSTR (x, 2), extra); | |
465 | XSTR (x, 4) = add_condition_to_string (XSTR (x, 4), extra); | |
466 | break; | |
467 | ||
468 | default: | |
469 | break; | |
470 | } | |
471 | } | |
472 | ||
b78fd164 RS |
473 | /* Apply the current iterator values to all attribute_uses. */ |
474 | ||
475 | static void | |
476 | apply_attribute_uses (void) | |
477 | { | |
478 | struct map_value *v; | |
479 | attribute_use *ause; | |
480 | unsigned int i; | |
481 | ||
9771b263 | 482 | FOR_EACH_VEC_ELT (attribute_uses, i, ause) |
b78fd164 RS |
483 | { |
484 | v = map_attr_string (ause->value); | |
485 | if (!v) | |
486 | fatal_with_file_and_line ("unknown iterator value `%s'", ause->value); | |
487 | ause->group->apply_iterator (ause->ptr, | |
488 | ause->group->find_builtin (v->string)); | |
489 | } | |
490 | } | |
491 | ||
492 | /* A htab_traverse callback for iterators. Add all used iterators | |
493 | to current_iterators. */ | |
032e8348 RS |
494 | |
495 | static int | |
b78fd164 | 496 | add_current_iterators (void **slot, void *data ATTRIBUTE_UNUSED) |
032e8348 | 497 | { |
3abcb3a7 | 498 | struct mapping *iterator; |
032e8348 | 499 | |
3abcb3a7 | 500 | iterator = (struct mapping *) *slot; |
b78fd164 | 501 | if (iterator->current_value) |
9771b263 | 502 | current_iterators.safe_push (iterator); |
032e8348 RS |
503 | return 1; |
504 | } | |
505 | ||
b78fd164 RS |
506 | /* Expand all iterators in the current rtx, which is given as ORIGINAL. |
507 | Build a list of expanded rtxes in the EXPR_LIST pointed to by QUEUE. */ | |
508 | ||
509 | static void | |
510 | apply_iterators (rtx original, rtx *queue) | |
511 | { | |
512 | unsigned int i; | |
513 | const char *condition; | |
514 | iterator_use *iuse; | |
515 | struct mapping *iterator; | |
516 | struct map_value *v; | |
517 | rtx x; | |
518 | ||
9771b263 | 519 | if (iterator_uses.is_empty ()) |
b78fd164 RS |
520 | { |
521 | /* Raise an error if any attributes were used. */ | |
522 | apply_attribute_uses (); | |
523 | XEXP (*queue, 0) = original; | |
524 | XEXP (*queue, 1) = NULL_RTX; | |
525 | return; | |
526 | } | |
527 | ||
528 | /* Clear out the iterators from the previous run. */ | |
9771b263 | 529 | FOR_EACH_VEC_ELT (current_iterators, i, iterator) |
b78fd164 | 530 | iterator->current_value = NULL; |
9771b263 | 531 | current_iterators.truncate (0); |
b78fd164 RS |
532 | |
533 | /* Mark the iterators that we need this time. */ | |
9771b263 | 534 | FOR_EACH_VEC_ELT (iterator_uses, i, iuse) |
b78fd164 RS |
535 | iuse->iterator->current_value = iuse->iterator->values; |
536 | ||
537 | /* Get the list of iterators that are in use, preserving the | |
538 | definition order within each group. */ | |
539 | htab_traverse (modes.iterators, add_current_iterators, NULL); | |
540 | htab_traverse (codes.iterators, add_current_iterators, NULL); | |
57a4717b | 541 | htab_traverse (ints.iterators, add_current_iterators, NULL); |
477c104e | 542 | htab_traverse (substs.iterators, add_current_iterators, NULL); |
9771b263 | 543 | gcc_assert (!current_iterators.is_empty ()); |
b78fd164 RS |
544 | |
545 | for (;;) | |
546 | { | |
547 | /* Apply the current iterator values. Accumulate a condition to | |
548 | say when the resulting rtx can be used. */ | |
52831d13 | 549 | condition = ""; |
9771b263 | 550 | FOR_EACH_VEC_ELT (iterator_uses, i, iuse) |
b78fd164 | 551 | { |
477c104e MK |
552 | if (iuse->iterator->group == &substs) |
553 | continue; | |
b78fd164 RS |
554 | v = iuse->iterator->current_value; |
555 | iuse->iterator->group->apply_iterator (iuse->ptr, v->number); | |
556 | condition = join_c_conditions (condition, v->string); | |
557 | } | |
558 | apply_attribute_uses (); | |
559 | x = copy_rtx_for_iterators (original); | |
560 | add_condition_to_rtx (x, condition); | |
561 | ||
477c104e MK |
562 | /* We apply subst iterator after RTL-template is copied, as during |
563 | subst-iterator processing, we could add an attribute to the | |
564 | RTL-template, and we don't want to do it in the original one. */ | |
565 | FOR_EACH_VEC_ELT (iterator_uses, i, iuse) | |
566 | { | |
567 | v = iuse->iterator->current_value; | |
568 | if (iuse->iterator->group == &substs) | |
569 | { | |
570 | iuse->ptr = x; | |
571 | current_iterator_name = iuse->iterator->name; | |
572 | iuse->iterator->group->apply_iterator (iuse->ptr, v->number); | |
573 | } | |
574 | } | |
b78fd164 RS |
575 | /* Add the new rtx to the end of the queue. */ |
576 | XEXP (*queue, 0) = x; | |
577 | XEXP (*queue, 1) = NULL_RTX; | |
578 | ||
579 | /* Lexicographically increment the iterator value sequence. | |
580 | That is, cycle through iterator values, starting from the right, | |
581 | and stopping when one of them doesn't wrap around. */ | |
9771b263 | 582 | i = current_iterators.length (); |
b78fd164 RS |
583 | for (;;) |
584 | { | |
585 | if (i == 0) | |
586 | return; | |
587 | i--; | |
9771b263 | 588 | iterator = current_iterators[i]; |
b78fd164 RS |
589 | iterator->current_value = iterator->current_value->next; |
590 | if (iterator->current_value) | |
591 | break; | |
592 | iterator->current_value = iterator->values; | |
593 | } | |
594 | ||
595 | /* At least one more rtx to go. Allocate room for it. */ | |
596 | XEXP (*queue, 1) = rtx_alloc (EXPR_LIST); | |
597 | queue = &XEXP (*queue, 1); | |
598 | } | |
599 | } | |
600 | ||
032e8348 | 601 | /* Add a new "mapping" structure to hashtable TABLE. NAME is the name |
c5e88b39 | 602 | of the mapping and GROUP is the group to which it belongs. */ |
032e8348 RS |
603 | |
604 | static struct mapping * | |
c5e88b39 | 605 | add_mapping (struct iterator_group *group, htab_t table, const char *name) |
032e8348 RS |
606 | { |
607 | struct mapping *m; | |
608 | void **slot; | |
609 | ||
610 | m = XNEW (struct mapping); | |
611 | m->name = xstrdup (name); | |
612 | m->group = group; | |
032e8348 | 613 | m->values = 0; |
b78fd164 | 614 | m->current_value = NULL; |
032e8348 RS |
615 | |
616 | slot = htab_find_slot (table, m, INSERT); | |
617 | if (*slot != 0) | |
c5e88b39 | 618 | fatal_with_file_and_line ("`%s' already defined", name); |
032e8348 RS |
619 | |
620 | *slot = m; | |
621 | return m; | |
622 | } | |
623 | ||
624 | /* Add the pair (NUMBER, STRING) to a list of map_value structures. | |
625 | END_PTR points to the current null terminator for the list; return | |
626 | a pointer the new null terminator. */ | |
627 | ||
628 | static struct map_value ** | |
629 | add_map_value (struct map_value **end_ptr, int number, const char *string) | |
630 | { | |
631 | struct map_value *value; | |
632 | ||
633 | value = XNEW (struct map_value); | |
634 | value->next = 0; | |
635 | value->number = number; | |
636 | value->string = string; | |
637 | ||
638 | *end_ptr = value; | |
639 | return &value->next; | |
640 | } | |
641 | ||
642 | /* Do one-time initialization of the mode and code attributes. */ | |
643 | ||
644 | static void | |
3abcb3a7 | 645 | initialize_iterators (void) |
032e8348 RS |
646 | { |
647 | struct mapping *lower, *upper; | |
648 | struct map_value **lower_ptr, **upper_ptr; | |
649 | char *copy, *p; | |
650 | int i; | |
651 | ||
9f418533 RS |
652 | modes.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0); |
653 | modes.iterators = htab_create (13, leading_string_hash, | |
654 | leading_string_eq_p, 0); | |
032e8348 | 655 | modes.find_builtin = find_mode; |
3abcb3a7 | 656 | modes.apply_iterator = apply_mode_iterator; |
032e8348 | 657 | |
9f418533 RS |
658 | codes.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0); |
659 | codes.iterators = htab_create (13, leading_string_hash, | |
660 | leading_string_eq_p, 0); | |
032e8348 | 661 | codes.find_builtin = find_code; |
3abcb3a7 | 662 | codes.apply_iterator = apply_code_iterator; |
032e8348 | 663 | |
57a4717b TB |
664 | ints.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0); |
665 | ints.iterators = htab_create (13, leading_string_hash, | |
666 | leading_string_eq_p, 0); | |
667 | ints.find_builtin = find_int; | |
668 | ints.apply_iterator = apply_int_iterator; | |
669 | ||
477c104e MK |
670 | substs.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0); |
671 | substs.iterators = htab_create (13, leading_string_hash, | |
672 | leading_string_eq_p, 0); | |
673 | substs.find_builtin = find_int; /* We don't use it, anyway. */ | |
674 | substs.apply_iterator = apply_subst_iterator; | |
675 | ||
c5e88b39 RS |
676 | lower = add_mapping (&modes, modes.attrs, "mode"); |
677 | upper = add_mapping (&modes, modes.attrs, "MODE"); | |
032e8348 RS |
678 | lower_ptr = &lower->values; |
679 | upper_ptr = &upper->values; | |
680 | for (i = 0; i < MAX_MACHINE_MODE; i++) | |
681 | { | |
682 | copy = xstrdup (GET_MODE_NAME (i)); | |
683 | for (p = copy; *p != 0; p++) | |
684 | *p = TOLOWER (*p); | |
685 | ||
686 | upper_ptr = add_map_value (upper_ptr, i, GET_MODE_NAME (i)); | |
687 | lower_ptr = add_map_value (lower_ptr, i, copy); | |
688 | } | |
689 | ||
c5e88b39 RS |
690 | lower = add_mapping (&codes, codes.attrs, "code"); |
691 | upper = add_mapping (&codes, codes.attrs, "CODE"); | |
032e8348 RS |
692 | lower_ptr = &lower->values; |
693 | upper_ptr = &upper->values; | |
694 | for (i = 0; i < NUM_RTX_CODE; i++) | |
695 | { | |
696 | copy = xstrdup (GET_RTX_NAME (i)); | |
697 | for (p = copy; *p != 0; p++) | |
698 | *p = TOUPPER (*p); | |
699 | ||
700 | lower_ptr = add_map_value (lower_ptr, i, GET_RTX_NAME (i)); | |
701 | upper_ptr = add_map_value (upper_ptr, i, copy); | |
702 | } | |
703 | } | |
0f40f9f7 ZW |
704 | \f |
705 | /* Provide a version of a function to read a long long if the system does | |
706 | not provide one. */ | |
707 | #if HOST_BITS_PER_WIDE_INT > HOST_BITS_PER_LONG && !defined(HAVE_ATOLL) && !defined(HAVE_ATOQ) | |
0c20a65f | 708 | HOST_WIDE_INT atoll (const char *); |
825c5408 | 709 | |
0f40f9f7 | 710 | HOST_WIDE_INT |
0c20a65f | 711 | atoll (const char *p) |
0f40f9f7 ZW |
712 | { |
713 | int neg = 0; | |
714 | HOST_WIDE_INT tmp_wide; | |
715 | ||
8e2e89f7 | 716 | while (ISSPACE (*p)) |
0f40f9f7 ZW |
717 | p++; |
718 | if (*p == '-') | |
719 | neg = 1, p++; | |
720 | else if (*p == '+') | |
721 | p++; | |
722 | ||
723 | tmp_wide = 0; | |
8e2e89f7 | 724 | while (ISDIGIT (*p)) |
0f40f9f7 ZW |
725 | { |
726 | HOST_WIDE_INT new_wide = tmp_wide*10 + (*p - '0'); | |
727 | if (new_wide < tmp_wide) | |
728 | { | |
729 | /* Return INT_MAX equiv on overflow. */ | |
f4f4d0f8 | 730 | tmp_wide = (~(unsigned HOST_WIDE_INT) 0) >> 1; |
0f40f9f7 ZW |
731 | break; |
732 | } | |
733 | tmp_wide = new_wide; | |
734 | p++; | |
735 | } | |
736 | ||
737 | if (neg) | |
738 | tmp_wide = -tmp_wide; | |
739 | return tmp_wide; | |
740 | } | |
741 | #endif | |
1c7352cd | 742 | \f |
82f8e3fd RS |
743 | /* Process a define_conditions directive, starting with the optional |
744 | space after the "define_conditions". The directive looks like this: | |
1c7352cd ZW |
745 | |
746 | (define_conditions [ | |
747 | (number "string") | |
748 | (number "string") | |
749 | ... | |
750 | ]) | |
751 | ||
752 | It's not intended to appear in machine descriptions. It is | |
753 | generated by (the program generated by) genconditions.c, and | |
754 | slipped in at the beginning of the sequence of MD files read by | |
755 | most of the other generators. */ | |
756 | static void | |
82f8e3fd | 757 | read_conditions (void) |
1c7352cd ZW |
758 | { |
759 | int c; | |
760 | ||
c5e88b39 | 761 | c = read_skip_spaces (); |
1c7352cd | 762 | if (c != '[') |
c5e88b39 | 763 | fatal_expected_char ('[', c); |
1c7352cd | 764 | |
c5e88b39 | 765 | while ( (c = read_skip_spaces ()) != ']') |
1c7352cd | 766 | { |
82f8e3fd | 767 | struct md_name name; |
1c7352cd ZW |
768 | char *expr; |
769 | int value; | |
770 | ||
771 | if (c != '(') | |
c5e88b39 | 772 | fatal_expected_char ('(', c); |
1c7352cd | 773 | |
82f8e3fd RS |
774 | read_name (&name); |
775 | validate_const_int (name.string); | |
776 | value = atoi (name.string); | |
1c7352cd | 777 | |
c5e88b39 | 778 | c = read_skip_spaces (); |
1c7352cd | 779 | if (c != '"') |
c5e88b39 RS |
780 | fatal_expected_char ('"', c); |
781 | expr = read_quoted_string (); | |
1c7352cd | 782 | |
c5e88b39 | 783 | c = read_skip_spaces (); |
1c7352cd | 784 | if (c != ')') |
c5e88b39 | 785 | fatal_expected_char (')', c); |
1c7352cd ZW |
786 | |
787 | add_c_test (expr, value); | |
788 | } | |
1c7352cd | 789 | } |
0f40f9f7 | 790 | |
53c98b1f | 791 | static void |
c5e88b39 | 792 | validate_const_int (const char *string) |
53c98b1f DD |
793 | { |
794 | const char *cp; | |
795 | int valid = 1; | |
796 | ||
797 | cp = string; | |
8e2e89f7 | 798 | while (*cp && ISSPACE (*cp)) |
53c98b1f DD |
799 | cp++; |
800 | if (*cp == '-' || *cp == '+') | |
801 | cp++; | |
802 | if (*cp == 0) | |
803 | valid = 0; | |
804 | for (; *cp; cp++) | |
805 | if (! ISDIGIT (*cp)) | |
bcb97fbd PCC |
806 | { |
807 | valid = 0; | |
808 | break; | |
809 | } | |
53c98b1f | 810 | if (!valid) |
c5e88b39 | 811 | fatal_with_file_and_line ("invalid decimal constant \"%s\"\n", string); |
53c98b1f DD |
812 | } |
813 | ||
b78fd164 | 814 | /* Record that PTR uses iterator ITERATOR. */ |
032e8348 | 815 | |
b78fd164 RS |
816 | static void |
817 | record_iterator_use (struct mapping *iterator, void *ptr) | |
818 | { | |
f32682ca | 819 | struct iterator_use iuse = {iterator, ptr}; |
9771b263 | 820 | iterator_uses.safe_push (iuse); |
b78fd164 RS |
821 | } |
822 | ||
823 | /* Record that PTR uses attribute VALUE, which must match a built-in | |
824 | value from group GROUP. */ | |
825 | ||
826 | static void | |
827 | record_attribute_use (struct iterator_group *group, void *ptr, | |
828 | const char *value) | |
829 | { | |
f32682ca | 830 | struct attribute_use ause = {group, value, ptr}; |
9771b263 | 831 | attribute_uses.safe_push (ause); |
b78fd164 RS |
832 | } |
833 | ||
834 | /* Interpret NAME as either a built-in value, iterator or attribute | |
835 | for group GROUP. PTR is the value to pass to GROUP's apply_iterator | |
836 | callback. */ | |
837 | ||
838 | static void | |
839 | record_potential_iterator_use (struct iterator_group *group, void *ptr, | |
840 | const char *name) | |
032e8348 RS |
841 | { |
842 | struct mapping *m; | |
b78fd164 | 843 | size_t len; |
032e8348 | 844 | |
b78fd164 RS |
845 | len = strlen (name); |
846 | if (name[0] == '<' && name[len - 1] == '>') | |
847 | { | |
848 | /* Copy the attribute string into permanent storage, without the | |
849 | angle brackets around it. */ | |
850 | obstack_grow0 (&string_obstack, name + 1, len - 2); | |
851 | record_attribute_use (group, ptr, XOBFINISH (&string_obstack, char *)); | |
852 | } | |
853 | else | |
854 | { | |
855 | m = (struct mapping *) htab_find (group->iterators, &name); | |
856 | if (m != 0) | |
857 | record_iterator_use (m, ptr); | |
858 | else | |
859 | group->apply_iterator (ptr, group->find_builtin (name)); | |
860 | } | |
032e8348 RS |
861 | } |
862 | ||
863 | /* Finish reading a declaration of the form: | |
864 | ||
865 | (define... <name> [<value1> ... <valuen>]) | |
866 | ||
c5e88b39 | 867 | from the MD file, where each <valuei> is either a bare symbol name or a |
032e8348 RS |
868 | "(<name> <string>)" pair. The "(define..." part has already been read. |
869 | ||
870 | Represent the declaration as a "mapping" structure; add it to TABLE | |
871 | (which belongs to GROUP) and return it. */ | |
872 | ||
873 | static struct mapping * | |
c5e88b39 | 874 | read_mapping (struct iterator_group *group, htab_t table) |
032e8348 | 875 | { |
82f8e3fd | 876 | struct md_name name; |
032e8348 RS |
877 | struct mapping *m; |
878 | struct map_value **end_ptr; | |
879 | const char *string; | |
880 | int number, c; | |
881 | ||
882 | /* Read the mapping name and create a structure for it. */ | |
82f8e3fd RS |
883 | read_name (&name); |
884 | m = add_mapping (group, table, name.string); | |
032e8348 | 885 | |
c5e88b39 | 886 | c = read_skip_spaces (); |
032e8348 | 887 | if (c != '[') |
c5e88b39 | 888 | fatal_expected_char ('[', c); |
032e8348 RS |
889 | |
890 | /* Read each value. */ | |
891 | end_ptr = &m->values; | |
c5e88b39 | 892 | c = read_skip_spaces (); |
032e8348 RS |
893 | do |
894 | { | |
895 | if (c != '(') | |
896 | { | |
897 | /* A bare symbol name that is implicitly paired to an | |
898 | empty string. */ | |
c5e88b39 | 899 | unread_char (c); |
82f8e3fd | 900 | read_name (&name); |
032e8348 RS |
901 | string = ""; |
902 | } | |
903 | else | |
904 | { | |
905 | /* A "(name string)" pair. */ | |
82f8e3fd | 906 | read_name (&name); |
c5e88b39 RS |
907 | string = read_string (false); |
908 | c = read_skip_spaces (); | |
032e8348 | 909 | if (c != ')') |
c5e88b39 | 910 | fatal_expected_char (')', c); |
032e8348 | 911 | } |
82f8e3fd | 912 | number = group->find_builtin (name.string); |
032e8348 | 913 | end_ptr = add_map_value (end_ptr, number, string); |
c5e88b39 | 914 | c = read_skip_spaces (); |
032e8348 RS |
915 | } |
916 | while (c != ']'); | |
917 | ||
032e8348 RS |
918 | return m; |
919 | } | |
920 | ||
477c104e MK |
921 | /* For iterator with name ATTR_NAME generate define_attr with values |
922 | 'yes' and 'no'. This attribute is used to mark templates to which | |
923 | define_subst ATTR_NAME should be applied. This attribute is set and | |
924 | defined implicitly and automatically. */ | |
925 | static void | |
926 | add_define_attr_for_define_subst (const char *attr_name, rtx *queue) | |
927 | { | |
928 | rtx const_str, return_rtx; | |
929 | ||
930 | return_rtx = rtx_alloc (DEFINE_ATTR); | |
931 | PUT_CODE (return_rtx, DEFINE_ATTR); | |
932 | ||
933 | const_str = rtx_alloc (CONST_STRING); | |
934 | PUT_CODE (const_str, CONST_STRING); | |
935 | XSTR (const_str, 0) = xstrdup ("no"); | |
936 | ||
937 | XSTR (return_rtx, 0) = xstrdup (attr_name); | |
938 | XSTR (return_rtx, 1) = xstrdup ("no,yes"); | |
939 | XEXP (return_rtx, 2) = const_str; | |
940 | ||
941 | XEXP (*queue, 0) = return_rtx; | |
942 | XEXP (*queue, 1) = NULL_RTX; | |
943 | } | |
944 | ||
945 | /* This routine generates DEFINE_SUBST_ATTR expression with operands | |
946 | ATTR_OPERANDS and places it to QUEUE. */ | |
947 | static void | |
948 | add_define_subst_attr (const char **attr_operands, rtx *queue) | |
949 | { | |
950 | rtx return_rtx; | |
951 | int i; | |
952 | ||
953 | return_rtx = rtx_alloc (DEFINE_SUBST_ATTR); | |
954 | PUT_CODE (return_rtx, DEFINE_SUBST_ATTR); | |
955 | ||
956 | for (i = 0; i < 4; i++) | |
957 | XSTR (return_rtx, i) = xstrdup (attr_operands[i]); | |
958 | ||
959 | XEXP (*queue, 0) = return_rtx; | |
960 | XEXP (*queue, 1) = NULL_RTX; | |
961 | } | |
962 | ||
963 | /* Read define_subst_attribute construction. It has next form: | |
964 | (define_subst_attribute <attribute_name> <iterator_name> <value1> <value2>) | |
965 | Attribute is substituted with value1 when no subst is applied and with | |
966 | value2 in the opposite case. | |
967 | Attributes are added to SUBST_ATTRS_TABLE. | |
968 | In case the iterator is encountered for the first time, it's added to | |
969 | SUBST_ITERS_TABLE. Also, implicit define_attr is generated. */ | |
970 | ||
971 | static void | |
972 | read_subst_mapping (htab_t subst_iters_table, htab_t subst_attrs_table, | |
973 | rtx *queue) | |
974 | { | |
975 | struct mapping *m; | |
976 | struct map_value **end_ptr; | |
977 | const char *attr_operands[4]; | |
978 | rtx * queue_elem = queue; | |
979 | int i; | |
980 | ||
981 | for (i = 0; i < 4; i++) | |
982 | attr_operands[i] = read_string (false); | |
983 | ||
984 | add_define_subst_attr (attr_operands, queue_elem); | |
985 | ||
986 | bind_subst_iter_and_attr (attr_operands[1], attr_operands[0]); | |
987 | ||
988 | m = (struct mapping *) htab_find (substs.iterators, &attr_operands[1]); | |
989 | if (!m) | |
990 | { | |
991 | m = add_mapping (&substs, subst_iters_table, attr_operands[1]); | |
992 | end_ptr = &m->values; | |
993 | end_ptr = add_map_value (end_ptr, 1, ""); | |
994 | end_ptr = add_map_value (end_ptr, 2, ""); | |
995 | ||
996 | /* Add element to the queue. */ | |
997 | XEXP (*queue, 1) = rtx_alloc (EXPR_LIST); | |
998 | queue_elem = &XEXP (*queue, 1); | |
999 | ||
1000 | add_define_attr_for_define_subst (attr_operands[1], queue_elem); | |
1001 | } | |
1002 | ||
1003 | m = add_mapping (&substs, subst_attrs_table, attr_operands[0]); | |
1004 | end_ptr = &m->values; | |
1005 | end_ptr = add_map_value (end_ptr, 1, attr_operands[2]); | |
1006 | end_ptr = add_map_value (end_ptr, 2, attr_operands[3]); | |
1007 | } | |
1008 | ||
3abcb3a7 | 1009 | /* Check newly-created code iterator ITERATOR to see whether every code has the |
b78fd164 | 1010 | same format. */ |
032e8348 RS |
1011 | |
1012 | static void | |
c5e88b39 | 1013 | check_code_iterator (struct mapping *iterator) |
032e8348 RS |
1014 | { |
1015 | struct map_value *v; | |
1016 | enum rtx_code bellwether; | |
1017 | ||
3abcb3a7 HPN |
1018 | bellwether = (enum rtx_code) iterator->values->number; |
1019 | for (v = iterator->values->next; v != 0; v = v->next) | |
032e8348 | 1020 | if (strcmp (GET_RTX_FORMAT (bellwether), GET_RTX_FORMAT (v->number)) != 0) |
c5e88b39 | 1021 | fatal_with_file_and_line ("code iterator `%s' combines " |
3abcb3a7 | 1022 | "different rtx formats", iterator->name); |
032e8348 RS |
1023 | } |
1024 | ||
600ab3fc RS |
1025 | /* Read an rtx-related declaration from the MD file, given that it |
1026 | starts with directive name RTX_NAME. Return true if it expands to | |
1027 | one or more rtxes (as defined by rtx.def). When returning true, | |
1028 | store the list of rtxes as an EXPR_LIST in *X. */ | |
0f40f9f7 | 1029 | |
57406c63 | 1030 | bool |
600ab3fc | 1031 | read_rtx (const char *rtx_name, rtx *x) |
0f40f9f7 | 1032 | { |
600ab3fc | 1033 | static rtx queue_head; |
032e8348 RS |
1034 | |
1035 | /* Do one-time initialization. */ | |
1036 | if (queue_head == 0) | |
1037 | { | |
3abcb3a7 | 1038 | initialize_iterators (); |
032e8348 RS |
1039 | queue_head = rtx_alloc (EXPR_LIST); |
1040 | } | |
1041 | ||
600ab3fc RS |
1042 | /* Handle various rtx-related declarations that aren't themselves |
1043 | encoded as rtxes. */ | |
1044 | if (strcmp (rtx_name, "define_conditions") == 0) | |
032e8348 | 1045 | { |
600ab3fc RS |
1046 | read_conditions (); |
1047 | return false; | |
032e8348 | 1048 | } |
600ab3fc RS |
1049 | if (strcmp (rtx_name, "define_mode_attr") == 0) |
1050 | { | |
1051 | read_mapping (&modes, modes.attrs); | |
1052 | return false; | |
1053 | } | |
1054 | if (strcmp (rtx_name, "define_mode_iterator") == 0) | |
1055 | { | |
1056 | read_mapping (&modes, modes.iterators); | |
1057 | return false; | |
1058 | } | |
1059 | if (strcmp (rtx_name, "define_code_attr") == 0) | |
1060 | { | |
1061 | read_mapping (&codes, codes.attrs); | |
1062 | return false; | |
1063 | } | |
1064 | if (strcmp (rtx_name, "define_code_iterator") == 0) | |
1065 | { | |
1066 | check_code_iterator (read_mapping (&codes, codes.iterators)); | |
1067 | return false; | |
1068 | } | |
57a4717b TB |
1069 | if (strcmp (rtx_name, "define_int_attr") == 0) |
1070 | { | |
1071 | read_mapping (&ints, ints.attrs); | |
1072 | return false; | |
1073 | } | |
1074 | if (strcmp (rtx_name, "define_int_iterator") == 0) | |
1075 | { | |
1076 | read_mapping (&ints, ints.iterators); | |
1077 | return false; | |
1078 | } | |
477c104e MK |
1079 | if (strcmp (rtx_name, "define_subst_attr") == 0) |
1080 | { | |
1081 | read_subst_mapping (substs.iterators, substs.attrs, &queue_head); | |
1082 | *x = queue_head; | |
1083 | ||
1084 | /* READ_SUBST_MAPPING could generate a new DEFINE_ATTR. Return | |
1085 | TRUE to process it. */ | |
1086 | return true; | |
1087 | } | |
600ab3fc | 1088 | |
b78fd164 | 1089 | apply_iterators (read_rtx_code (rtx_name), &queue_head); |
9771b263 DN |
1090 | iterator_uses.truncate (0); |
1091 | attribute_uses.truncate (0); | |
032e8348 | 1092 | |
600ab3fc | 1093 | *x = queue_head; |
57406c63 | 1094 | return true; |
032e8348 RS |
1095 | } |
1096 | ||
600ab3fc RS |
1097 | /* Subroutine of read_rtx and read_nested_rtx. CODE_NAME is the name of |
1098 | either an rtx code or a code iterator. Parse the rest of the rtx and | |
b78fd164 | 1099 | return it. */ |
032e8348 RS |
1100 | |
1101 | static rtx | |
b78fd164 | 1102 | read_rtx_code (const char *code_name) |
032e8348 RS |
1103 | { |
1104 | int i; | |
b78fd164 | 1105 | RTX_CODE code; |
477c104e | 1106 | struct mapping *iterator, *m; |
b3694847 | 1107 | const char *format_ptr; |
82f8e3fd | 1108 | struct md_name name; |
0f40f9f7 | 1109 | rtx return_rtx; |
b3694847 | 1110 | int c; |
0f40f9f7 | 1111 | HOST_WIDE_INT tmp_wide; |
477c104e MK |
1112 | char *str; |
1113 | char *start, *end, *ptr; | |
1114 | char tmpstr[256]; | |
0f40f9f7 | 1115 | |
0f40f9f7 ZW |
1116 | /* Linked list structure for making RTXs: */ |
1117 | struct rtx_list | |
1118 | { | |
1119 | struct rtx_list *next; | |
1120 | rtx value; /* Value of this node. */ | |
1121 | }; | |
1122 | ||
b78fd164 RS |
1123 | /* If this code is an iterator, build the rtx using the iterator's |
1124 | first value. */ | |
1125 | iterator = (struct mapping *) htab_find (codes.iterators, &code_name); | |
1126 | if (iterator != 0) | |
1127 | code = (enum rtx_code) iterator->values->number; | |
1128 | else | |
1129 | code = (enum rtx_code) codes.find_builtin (code_name); | |
0f40f9f7 ZW |
1130 | |
1131 | /* If we end up with an insn expression then we free this space below. */ | |
b78fd164 RS |
1132 | return_rtx = rtx_alloc (code); |
1133 | format_ptr = GET_RTX_FORMAT (code); | |
1134 | PUT_CODE (return_rtx, code); | |
1135 | ||
1136 | if (iterator) | |
1137 | record_iterator_use (iterator, return_rtx); | |
0f40f9f7 ZW |
1138 | |
1139 | /* If what follows is `: mode ', read it and | |
1140 | store the mode in the rtx. */ | |
1141 | ||
c5e88b39 | 1142 | i = read_skip_spaces (); |
0f40f9f7 ZW |
1143 | if (i == ':') |
1144 | { | |
82f8e3fd | 1145 | read_name (&name); |
b78fd164 | 1146 | record_potential_iterator_use (&modes, return_rtx, name.string); |
0f40f9f7 ZW |
1147 | } |
1148 | else | |
c5e88b39 | 1149 | unread_char (i); |
0f40f9f7 | 1150 | |
ecce923e RS |
1151 | for (i = 0; format_ptr[i] != 0; i++) |
1152 | switch (format_ptr[i]) | |
0f40f9f7 ZW |
1153 | { |
1154 | /* 0 means a field for internal use only. | |
1155 | Don't expect it to be present in the input. */ | |
1156 | case '0': | |
1157 | break; | |
1158 | ||
1159 | case 'e': | |
1160 | case 'u': | |
b78fd164 | 1161 | XEXP (return_rtx, i) = read_nested_rtx (); |
0f40f9f7 ZW |
1162 | break; |
1163 | ||
1164 | case 'V': | |
1165 | /* 'V' is an optional vector: if a closeparen follows, | |
1166 | just store NULL for this element. */ | |
c5e88b39 RS |
1167 | c = read_skip_spaces (); |
1168 | unread_char (c); | |
0f40f9f7 ZW |
1169 | if (c == ')') |
1170 | { | |
1171 | XVEC (return_rtx, i) = 0; | |
1172 | break; | |
a6a2274a | 1173 | } |
0f40f9f7 ZW |
1174 | /* Now process the vector. */ |
1175 | ||
1176 | case 'E': | |
1177 | { | |
1178 | /* Obstack to store scratch vector in. */ | |
1179 | struct obstack vector_stack; | |
1180 | int list_counter = 0; | |
1181 | rtvec return_vec = NULL_RTVEC; | |
1182 | ||
c5e88b39 | 1183 | c = read_skip_spaces (); |
0f40f9f7 | 1184 | if (c != '[') |
c5e88b39 | 1185 | fatal_expected_char ('[', c); |
0f40f9f7 | 1186 | |
a1105617 | 1187 | /* Add expressions to a list, while keeping a count. */ |
0f40f9f7 | 1188 | obstack_init (&vector_stack); |
c5e88b39 | 1189 | while ((c = read_skip_spaces ()) && c != ']') |
0f40f9f7 | 1190 | { |
d33da5cd | 1191 | if (c == EOF) |
c5e88b39 RS |
1192 | fatal_expected_char (']', c); |
1193 | unread_char (c); | |
0f40f9f7 | 1194 | list_counter++; |
b78fd164 | 1195 | obstack_ptr_grow (&vector_stack, read_nested_rtx ()); |
0f40f9f7 ZW |
1196 | } |
1197 | if (list_counter > 0) | |
1198 | { | |
1199 | return_vec = rtvec_alloc (list_counter); | |
1200 | memcpy (&return_vec->elem[0], obstack_finish (&vector_stack), | |
1201 | list_counter * sizeof (rtx)); | |
1202 | } | |
c5d97f6e | 1203 | else if (format_ptr[i] == 'E') |
c5e88b39 | 1204 | fatal_with_file_and_line ("vector must have at least one element"); |
0f40f9f7 ZW |
1205 | XVEC (return_rtx, i) = return_vec; |
1206 | obstack_free (&vector_stack, NULL); | |
1207 | /* close bracket gotten */ | |
1208 | } | |
1209 | break; | |
1210 | ||
1211 | case 'S': | |
1f3b37a3 | 1212 | case 'T': |
0f40f9f7 ZW |
1213 | case 's': |
1214 | { | |
1215 | char *stringbuf; | |
62d45923 RS |
1216 | int star_if_braced; |
1217 | ||
c5e88b39 RS |
1218 | c = read_skip_spaces (); |
1219 | unread_char (c); | |
62d45923 RS |
1220 | if (c == ')') |
1221 | { | |
1222 | /* 'S' fields are optional and should be NULL if no string | |
1223 | was given. Also allow normal 's' and 'T' strings to be | |
1224 | omitted, treating them in the same way as empty strings. */ | |
ecce923e | 1225 | XSTR (return_rtx, i) = (format_ptr[i] == 'S' ? NULL : ""); |
62d45923 RS |
1226 | break; |
1227 | } | |
0f40f9f7 ZW |
1228 | |
1229 | /* The output template slot of a DEFINE_INSN, | |
1230 | DEFINE_INSN_AND_SPLIT, or DEFINE_PEEPHOLE automatically | |
1231 | gets a star inserted as its first character, if it is | |
1232 | written with a brace block instead of a string constant. */ | |
ecce923e | 1233 | star_if_braced = (format_ptr[i] == 'T'); |
a6a2274a | 1234 | |
c5e88b39 | 1235 | stringbuf = read_string (star_if_braced); |
0f40f9f7 ZW |
1236 | |
1237 | /* For insn patterns, we want to provide a default name | |
1238 | based on the file and line, like "*foo.md:12", if the | |
1239 | given name is blank. These are only for define_insn and | |
1240 | define_insn_and_split, to aid debugging. */ | |
1241 | if (*stringbuf == '\0' | |
1242 | && i == 0 | |
1243 | && (GET_CODE (return_rtx) == DEFINE_INSN | |
1244 | || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT)) | |
1245 | { | |
1246 | char line_name[20]; | |
d2a3ce4e | 1247 | const char *fn = (read_md_filename ? read_md_filename : "rtx"); |
0f40f9f7 ZW |
1248 | const char *slash; |
1249 | for (slash = fn; *slash; slash ++) | |
1250 | if (*slash == '/' || *slash == '\\' || *slash == ':') | |
1251 | fn = slash + 1; | |
a269d6c8 RS |
1252 | obstack_1grow (&string_obstack, '*'); |
1253 | obstack_grow (&string_obstack, fn, strlen (fn)); | |
d2a3ce4e | 1254 | sprintf (line_name, ":%d", read_md_lineno); |
a269d6c8 | 1255 | obstack_grow (&string_obstack, line_name, strlen (line_name)+1); |
7973fd2a | 1256 | stringbuf = XOBFINISH (&string_obstack, char *); |
0f40f9f7 ZW |
1257 | } |
1258 | ||
477c104e MK |
1259 | /* Find attr-names in the string. */ |
1260 | ptr = &tmpstr[0]; | |
1261 | end = stringbuf; | |
1262 | while ((start = strchr (end, '<')) && (end = strchr (start, '>'))) | |
1263 | { | |
1264 | if ((end - start - 1 > 0) | |
1265 | && (end - start - 1 < (int)sizeof (tmpstr))) | |
1266 | { | |
1267 | strncpy (tmpstr, start+1, end-start-1); | |
1268 | tmpstr[end-start-1] = 0; | |
1269 | end++; | |
1270 | } | |
1271 | else | |
1272 | break; | |
1273 | m = (struct mapping *) htab_find (substs.attrs, &ptr); | |
1274 | if (m != 0) | |
1275 | { | |
1276 | /* Here we should find linked subst-iter. */ | |
1277 | str = find_subst_iter_by_attr (ptr); | |
1278 | if (str) | |
1279 | m = (struct mapping *) htab_find (substs.iterators, &str); | |
1280 | else | |
1281 | m = 0; | |
1282 | } | |
1283 | if (m != 0) | |
1284 | record_iterator_use (m, return_rtx); | |
1285 | } | |
1286 | ||
1f3b37a3 ZW |
1287 | if (star_if_braced) |
1288 | XTMPL (return_rtx, i) = stringbuf; | |
1289 | else | |
1290 | XSTR (return_rtx, i) = stringbuf; | |
0f40f9f7 ZW |
1291 | } |
1292 | break; | |
1293 | ||
1294 | case 'w': | |
82f8e3fd RS |
1295 | read_name (&name); |
1296 | validate_const_int (name.string); | |
0f40f9f7 | 1297 | #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT |
82f8e3fd | 1298 | tmp_wide = atoi (name.string); |
0f40f9f7 ZW |
1299 | #else |
1300 | #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG | |
82f8e3fd | 1301 | tmp_wide = atol (name.string); |
0f40f9f7 ZW |
1302 | #else |
1303 | /* Prefer atoll over atoq, since the former is in the ISO C99 standard. | |
1304 | But prefer not to use our hand-rolled function above either. */ | |
1305 | #if defined(HAVE_ATOLL) || !defined(HAVE_ATOQ) | |
82f8e3fd | 1306 | tmp_wide = atoll (name.string); |
0f40f9f7 | 1307 | #else |
82f8e3fd | 1308 | tmp_wide = atoq (name.string); |
0f40f9f7 ZW |
1309 | #endif |
1310 | #endif | |
1311 | #endif | |
1312 | XWINT (return_rtx, i) = tmp_wide; | |
1313 | break; | |
1314 | ||
1315 | case 'i': | |
1316 | case 'n': | |
57a4717b | 1317 | /* Can be an iterator or an integer constant. */ |
82f8e3fd | 1318 | read_name (&name); |
57a4717b TB |
1319 | record_potential_iterator_use (&ints, &XINT (return_rtx, i), |
1320 | name.string); | |
0f40f9f7 ZW |
1321 | break; |
1322 | ||
1323 | default: | |
0e61db61 | 1324 | gcc_unreachable (); |
0f40f9f7 ZW |
1325 | } |
1326 | ||
600ab3fc RS |
1327 | c = read_skip_spaces (); |
1328 | /* Syntactic sugar for AND and IOR, allowing Lisp-like | |
1329 | arbitrary number of arguments for them. */ | |
1330 | if (c == '(' | |
1331 | && (GET_CODE (return_rtx) == AND | |
1332 | || GET_CODE (return_rtx) == IOR)) | |
b78fd164 | 1333 | return read_rtx_variadic (return_rtx); |
600ab3fc RS |
1334 | |
1335 | unread_char (c); | |
1336 | return return_rtx; | |
1337 | } | |
1338 | ||
b78fd164 | 1339 | /* Read a nested rtx construct from the MD file and return it. */ |
600ab3fc RS |
1340 | |
1341 | static rtx | |
b78fd164 | 1342 | read_nested_rtx (void) |
600ab3fc RS |
1343 | { |
1344 | struct md_name name; | |
1345 | int c; | |
1346 | rtx return_rtx; | |
1347 | ||
1348 | c = read_skip_spaces (); | |
1349 | if (c != '(') | |
1350 | fatal_expected_char ('(', c); | |
1351 | ||
1352 | read_name (&name); | |
1353 | if (strcmp (name.string, "nil") == 0) | |
1354 | return_rtx = NULL; | |
1355 | else | |
b78fd164 | 1356 | return_rtx = read_rtx_code (name.string); |
600ab3fc | 1357 | |
c5e88b39 | 1358 | c = read_skip_spaces (); |
0f40f9f7 | 1359 | if (c != ')') |
600ab3fc | 1360 | fatal_expected_char (')', c); |
0f40f9f7 ZW |
1361 | |
1362 | return return_rtx; | |
1363 | } | |
6e7a4706 ZW |
1364 | |
1365 | /* Mutually recursive subroutine of read_rtx which reads | |
1366 | (thing x1 x2 x3 ...) and produces RTL as if | |
1367 | (thing x1 (thing x2 (thing x3 ...))) had been written. | |
1368 | When called, FORM is (thing x1 x2), and the file position | |
1369 | is just past the leading parenthesis of x3. Only works | |
1370 | for THINGs which are dyadic expressions, e.g. AND, IOR. */ | |
1371 | static rtx | |
b78fd164 | 1372 | read_rtx_variadic (rtx form) |
6e7a4706 ZW |
1373 | { |
1374 | char c = '('; | |
1375 | rtx p = form, q; | |
1376 | ||
1377 | do | |
1378 | { | |
c5e88b39 | 1379 | unread_char (c); |
6e7a4706 ZW |
1380 | |
1381 | q = rtx_alloc (GET_CODE (p)); | |
1382 | PUT_MODE (q, GET_MODE (p)); | |
1383 | ||
1384 | XEXP (q, 0) = XEXP (p, 1); | |
b78fd164 | 1385 | XEXP (q, 1) = read_nested_rtx (); |
b8698a0f | 1386 | |
6e7a4706 ZW |
1387 | XEXP (p, 1) = q; |
1388 | p = q; | |
c5e88b39 | 1389 | c = read_skip_spaces (); |
6e7a4706 ZW |
1390 | } |
1391 | while (c == '('); | |
600ab3fc | 1392 | unread_char (c); |
6e7a4706 ZW |
1393 | return form; |
1394 | } |