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