1/* RTL reader for GCC.
2 Copyright (C) 1987-2025 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
19
20/* This file is compiled twice: once for the generator programs
21 once for the compiler. */
22#ifdef GENERATOR_FILE
23#include "bconfig.h"
24#else
25#include "config.h"
26#endif
27
28/* Disable rtl checking; it conflicts with the iterator handling. */
29#undef ENABLE_RTL_CHECKING
30
31#include "system.h"
32#include "coretypes.h"
33#include "tm.h"
34#include "rtl.h"
35#include "obstack.h"
36#include "read-md.h"
37#include "gensupport.h"
38
39/* One element in a singly-linked list of (integer, string) pairs. */
40struct map_value {
41 struct map_value *next;
42 int number;
43 const char *string;
44};
45
46/* Maps an iterator or attribute name to a list of (integer, string) pairs.
47 The integers are iterator values; the strings are either C conditions
48 or attribute values. */
49struct mapping {
50 /* The name of the iterator or attribute. */
51 const char *name;
52
53 /* The group (modes or codes) to which the iterator or attribute belongs. */
54 struct iterator_group *group;
55
56 /* The list of (integer, string) pairs. */
57 struct map_value *values;
58
59 /* For iterators, records the current value of the iterator. */
60 struct map_value *current_value;
61};
62
63/* A structure for abstracting the common parts of iterators. */
64struct iterator_group {
65 /* Tables of "mapping" structures, one for attributes and one for
66 iterators. */
67 htab_t attrs, iterators;
68
69 /* The C++ type of the iterator, such as "machine_mode" for modes. */
70 const char *type;
71
72 /* Treat the given string as the name of a standard mode, etc., and
73 return its integer value. */
74 HOST_WIDE_INT (*find_builtin) (const char *);
75
76 /* Make the given rtx use the iterator value given by the third argument.
77 If the iterator applies to operands, the second argument gives the
78 operand index, otherwise it is ignored. */
79 void (*apply_iterator) (rtx, unsigned int, HOST_WIDE_INT);
80
81 /* Return the C token for the given standard mode, code, etc. */
82 const char *(*get_c_token) (int);
83
84 /* True if each iterator name should be treated as an attribute that
85 maps to the C token produced by get_c_token. This means that for
86 an iterator ITER, <ITER> can be used in strings to refer to the
87 current value of ITER, as a C token. */
88 bool has_self_attr;
89};
90
91/* Records one use of an iterator. */
92struct iterator_use {
93 /* The iterator itself. */
94 struct mapping *iterator;
95
96 /* The location of the use, as passed to the apply_iterator callback.
97 The index is the number of the operand that used the iterator
98 if applicable, otherwise it is ignored. */
99 rtx x;
100 unsigned int index;
101};
102
103/* Records one use of an attribute (the "<[iterator:]attribute>" syntax)
104 in a non-string rtx field. */
105struct attribute_use {
106 /* The group that describes the use site. */
107 struct iterator_group *group;
108
109 /* The location at which the use occurs. */
110 file_location loc;
111
112 /* The name of the attribute, possibly with an "iterator:" prefix. */
113 const char *value;
114
115 /* The location of the use, as passed to GROUP's apply_iterator callback.
116 The index is the number of the operand that used the iterator
117 if applicable, otherwise it is ignored. */
118 rtx x;
119 unsigned int index;
120};
121
122/* This struct is used to link subst_attr named ATTR_NAME with
123 corresponding define_subst named ITER_NAME. */
124struct subst_attr_to_iter_mapping
125{
126 char *attr_name;
127 char *iter_name;
128};
129
130/* Hash-table to store links between subst-attributes and
131 define_substs. */
132htab_t subst_attr_to_iter_map = NULL;
133/* This global stores name of subst-iterator which is currently being
134 processed. */
135const char *current_iterator_name;
136
137static void validate_const_int (const char *);
138static void one_time_initialization (void);
139
140/* Global singleton. */
141rtx_reader *rtx_reader_ptr = NULL;
142
143/* The mode and code iterator structures. */
144static struct iterator_group modes, codes, ints, substs;
145
146/* All iterators used in the current rtx. */
147static vec<mapping *> current_iterators;
148
149/* The list of all iterator uses in the current rtx. */
150static vec<iterator_use> iterator_uses;
151
152/* The list of all attribute uses in the current rtx. */
153static vec<attribute_use> attribute_uses;
154
155/* Provide a version of a function to read a long long if the system does
156 not provide one. */
157#if (HOST_BITS_PER_WIDE_INT > HOST_BITS_PER_LONG \
158 && !HAVE_DECL_ATOLL \
159 && !defined (HAVE_ATOQ))
160HOST_WIDE_INT atoll (const char *);
161
162HOST_WIDE_INT
163atoll (const char *p)
164{
165 int neg = 0;
166 HOST_WIDE_INT tmp_wide;
167
168 while (ISSPACE (*p))
169 p++;
170 if (*p == '-')
171 neg = 1, p++;
172 else if (*p == '+')
173 p++;
174
175 tmp_wide = 0;
176 while (ISDIGIT (*p))
177 {
178 HOST_WIDE_INT new_wide = tmp_wide*10 + (*p - '0');
179 if (new_wide < tmp_wide)
180 {
181 /* Return INT_MAX equiv on overflow. */
182 tmp_wide = HOST_WIDE_INT_M1U >> 1;
183 break;
184 }
185 tmp_wide = new_wide;
186 p++;
187 }
188
189 if (neg)
190 tmp_wide = -tmp_wide;
191 return tmp_wide;
192}
193#endif
194
195/* Implementations of the iterator_group callbacks for modes. */
196
197static HOST_WIDE_INT
198find_mode (const char *name)
199{
200 int i;
201
202 for (i = 0; i < NUM_MACHINE_MODES; i++)
203 if (strcmp (GET_MODE_NAME (i), s2: name) == 0)
204 return i;
205
206 fatal_with_file_and_line ("unknown mode `%s'", name);
207}
208
209static void
210apply_mode_iterator (rtx x, unsigned int, HOST_WIDE_INT mode)
211{
212 PUT_MODE (x, (machine_mode) mode);
213}
214
215static const char *
216get_mode_token (int mode)
217{
218 return concat ("E_", GET_MODE_NAME (mode), "mode", NULL);
219}
220
221/* In compact dumps, the code of insns is prefixed with "c", giving "cinsn",
222 "cnote" etc, and CODE_LABEL is special-cased as "clabel". */
223
224struct compact_insn_name {
225 RTX_CODE code;
226 const char *name;
227};
228
229static const compact_insn_name compact_insn_names[] = {
230 { .code: DEBUG_INSN, .name: "cdebug_insn" },
231 { .code: INSN, .name: "cinsn" },
232 { .code: JUMP_INSN, .name: "cjump_insn" },
233 { .code: CALL_INSN, .name: "ccall_insn" },
234 { .code: JUMP_TABLE_DATA, .name: "cjump_table_data" },
235 { .code: BARRIER, .name: "cbarrier" },
236 { .code: CODE_LABEL, .name: "clabel" },
237 { .code: NOTE, .name: "cnote" }
238};
239
240/* Return the rtx code for NAME, or UNKNOWN if NAME isn't a valid rtx code. */
241
242static rtx_code
243maybe_find_code (const char *name)
244{
245 for (int i = 0; i < NUM_RTX_CODE; i++)
246 if (strcmp (GET_RTX_NAME (i), s2: name) == 0)
247 return (rtx_code) i;
248
249 for (int i = 0; i < (signed)ARRAY_SIZE (compact_insn_names); i++)
250 if (strcmp (s1: compact_insn_names[i].name, s2: name) == 0)
251 return compact_insn_names[i].code;
252
253 return UNKNOWN;
254}
255
256/* Implementations of the iterator_group callbacks for codes. */
257
258static HOST_WIDE_INT
259find_code (const char *name)
260{
261 rtx_code code = maybe_find_code (name);
262 if (code == UNKNOWN)
263 fatal_with_file_and_line ("unknown rtx code `%s'", name);
264 return code;
265}
266
267static void
268apply_code_iterator (rtx x, unsigned int, HOST_WIDE_INT code)
269{
270 PUT_CODE (x, (enum rtx_code) code);
271}
272
273static const char *
274get_code_token (int code)
275{
276 char *name = xstrdup (GET_RTX_NAME (code));
277 for (int i = 0; name[i]; ++i)
278 name[i] = TOUPPER (name[i]);
279 return name;
280}
281
282/* Implementations of the iterator_group callbacks for ints. */
283
284/* Since GCC does not construct a table of valid constants,
285 we have to accept any int as valid. No cross-checking can
286 be done. */
287
288static HOST_WIDE_INT
289find_int (const char *name)
290{
291 HOST_WIDE_INT tmp;
292
293 struct md_constant tmp_def;
294 tmp_def.name = const_cast<char *> (name);
295 auto htab = rtx_reader_ptr->get_md_constants ();
296 if (auto def = (struct md_constant *) htab_find (htab, &tmp_def))
297 name = def->value;
298
299 validate_const_int (name);
300#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
301 tmp = atoi (name);
302#else
303#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
304 tmp = atol (nptr: name);
305#else
306 /* Prefer atoll over atoq, since the former is in the ISO C99 standard.
307 But prefer not to use our hand-rolled function above either. */
308#if HAVE_DECL_ATOLL || !defined(HAVE_ATOQ)
309 tmp = atoll (name);
310#else
311 tmp = atoq (name);
312#endif
313#endif
314#endif
315 return tmp;
316}
317
318static void
319apply_int_iterator (rtx x, unsigned int index, HOST_WIDE_INT value)
320{
321 RTX_CODE code = GET_CODE (x);
322 const char *format_ptr = GET_RTX_FORMAT (code);
323
324 switch (format_ptr[index])
325 {
326 case 'i':
327 case 'n':
328 XINT (x, index) = value;
329 break;
330 case 'L':
331 XLOC (x, index) = value;
332 break;
333 case 'w':
334 XWINT (x, index) = value;
335 break;
336 case 'p':
337 gcc_assert (code == SUBREG);
338 SUBREG_BYTE (x) = value;
339 break;
340 default:
341 gcc_unreachable ();
342 }
343}
344
345static const char *
346get_int_token (int value)
347{
348 char buffer[HOST_BITS_PER_INT + 1];
349 sprintf (s: buffer, format: "%d", value);
350 return xstrdup (buffer);
351}
352
353#ifdef GENERATOR_FILE
354
355/* This routine adds attribute or does nothing depending on VALUE. When
356 VALUE is 1, it does nothing - the first duplicate of original
357 template is kept untouched when it's subjected to a define_subst.
358 When VALUE isn't 1, the routine modifies RTL-template RT, adding
359 attribute, named exactly as define_subst, which later will be
360 applied. If such attribute has already been added, then no the
361 routine has no effect. */
362static void
363apply_subst_iterator (rtx rt, unsigned int, HOST_WIDE_INT value)
364{
365 rtx new_attr;
366 rtvec attrs_vec, new_attrs_vec;
367 int i;
368 /* define_split has no attributes. */
369 if (value == 1 || GET_CODE (rt) == DEFINE_SPLIT)
370 return;
371 gcc_assert (GET_CODE (rt) == DEFINE_INSN
372 || GET_CODE (rt) == DEFINE_INSN_AND_SPLIT
373 || GET_CODE (rt) == DEFINE_INSN_AND_REWRITE
374 || GET_CODE (rt) == DEFINE_EXPAND);
375
376 int attrs = (GET_CODE (rt) == DEFINE_INSN_AND_SPLIT ? 7
377 : GET_CODE (rt) == DEFINE_INSN_AND_REWRITE ? 6 : 4);
378 attrs_vec = XVEC (rt, attrs);
379
380 /* If we've already added attribute 'current_iterator_name', then we
381 have nothing to do now. */
382 if (attrs_vec)
383 {
384 for (i = 0; i < GET_NUM_ELEM (attrs_vec); i++)
385 {
386 if (strcmp (XSTR (attrs_vec->elem[i], 0), s2: current_iterator_name) == 0)
387 return;
388 }
389 }
390
391 /* Add attribute with subst name - it serves as a mark for
392 define_subst which later would be applied to this pattern. */
393 new_attr = rtx_alloc (SET_ATTR);
394 PUT_CODE (new_attr, SET_ATTR);
395 XSTR (new_attr, 0) = xstrdup (current_iterator_name);
396 XSTR (new_attr, 1) = xstrdup ("yes");
397
398 if (!attrs_vec)
399 {
400 new_attrs_vec = rtvec_alloc (1);
401 new_attrs_vec->elem[0] = new_attr;
402 }
403 else
404 {
405 new_attrs_vec = rtvec_alloc (GET_NUM_ELEM (attrs_vec) + 1);
406 memcpy (dest: &new_attrs_vec->elem[0], src: &attrs_vec->elem[0],
407 GET_NUM_ELEM (attrs_vec) * sizeof (rtx));
408 new_attrs_vec->elem[GET_NUM_ELEM (attrs_vec)] = new_attr;
409 }
410 XVEC (rt, attrs) = new_attrs_vec;
411}
412
413/* Map subst-attribute ATTR to subst iterator ITER. */
414
415static void
416bind_subst_iter_and_attr (const char *iter, const char *attr)
417{
418 struct subst_attr_to_iter_mapping *value;
419 void **slot;
420 if (!subst_attr_to_iter_map)
421 subst_attr_to_iter_map =
422 htab_create (1, leading_string_hash, leading_string_eq_p, 0);
423 value = XNEW (struct subst_attr_to_iter_mapping);
424 value->attr_name = xstrdup (attr);
425 value->iter_name = xstrdup (iter);
426 slot = htab_find_slot (subst_attr_to_iter_map, value, INSERT);
427 *slot = value;
428}
429
430#endif /* #ifdef GENERATOR_FILE */
431
432/* Return name of a subst-iterator, corresponding to subst-attribute ATTR. */
433
434static char*
435find_subst_iter_by_attr (const char *attr)
436{
437 char *iter_name = NULL;
438 struct subst_attr_to_iter_mapping *value;
439 value = (struct subst_attr_to_iter_mapping*)
440 htab_find (subst_attr_to_iter_map, &attr);
441 if (value)
442 iter_name = value->iter_name;
443 return iter_name;
444}
445
446/* Map attribute string P to its current value. Return null if the attribute
447 isn't known. If ITERATOR_OUT is nonnull, store the associated iterator
448 there. Report any errors against location LOC. */
449
450static struct map_value *
451map_attr_string (file_location loc, const char *p, mapping **iterator_out = 0)
452{
453 const char *attr;
454 struct mapping *iterator;
455 unsigned int i;
456 struct mapping *m;
457 struct map_value *v;
458 int iterator_name_len;
459 struct map_value *res = NULL;
460 struct mapping *prev = NULL;
461
462 /* Peel off any "iterator:" prefix. Set ATTR to the start of the
463 attribute name. */
464 attr = strchr (s: p, c: ':');
465 if (attr == 0)
466 {
467 iterator_name_len = -1;
468 attr = p;
469 }
470 else
471 {
472 iterator_name_len = attr - p;
473 attr++;
474 }
475
476 FOR_EACH_VEC_ELT (current_iterators, i, iterator)
477 {
478 /* If an iterator name was specified, check that it matches. */
479 if (iterator_name_len >= 0
480 && (strncmp (s1: p, s2: iterator->name, n: iterator_name_len) != 0
481 || iterator->name[iterator_name_len] != 0))
482 continue;
483
484 if (iterator->group->has_self_attr
485 && strcmp (s1: attr, s2: iterator->name) == 0)
486 {
487 if (iterator_out)
488 *iterator_out = iterator;
489 int number = iterator->current_value->number;
490 const char *string = iterator->group->get_c_token (number);
491 if (res && strcmp (s1: string, s2: res->string) != 0)
492 {
493 error_at (loc, "ambiguous attribute '%s'; could be"
494 " '%s' (via '%s:%s') or '%s' (via '%s:%s')",
495 attr, res->string, prev->name, attr,
496 string, iterator->name, attr);
497 return res;
498 }
499 prev = iterator;
500 res = new map_value { .next: nullptr, .number: number, .string: string };
501 }
502
503 /* Find the attribute specification. */
504 m = (struct mapping *) htab_find (iterator->group->attrs, &attr);
505 if (m)
506 {
507 /* In contrast to code/mode/int iterators, attributes of subst
508 iterators are linked to one specific subst-iterator. So, if
509 we are dealing with subst-iterator, we should check if it's
510 the one which linked with the given attribute. */
511 if (iterator->group == &substs)
512 {
513 char *iter_name = find_subst_iter_by_attr (attr);
514 if (strcmp (s1: iter_name, s2: iterator->name) != 0)
515 continue;
516 }
517 /* Find the attribute value associated with the current
518 iterator value. */
519 for (v = m->values; v; v = v->next)
520 if (v->number == iterator->current_value->number)
521 {
522 if (res && strcmp (s1: v->string, s2: res->string) != 0)
523 {
524 error_at (loc, "ambiguous attribute '%s'; could be"
525 " '%s' (via '%s:%s') or '%s' (via '%s:%s')",
526 attr, res->string, prev->name, attr,
527 v->string, iterator->name, attr);
528 return v;
529 }
530 if (iterator_out)
531 *iterator_out = iterator;
532 prev = iterator;
533 res = v;
534 }
535 }
536 }
537 return res;
538}
539
540/* Apply the current iterator values to STRING. Return the new string
541 if any changes were needed, otherwise return STRING itself. */
542
543const char *
544md_reader::apply_iterator_to_string (const char *string)
545{
546 char *base, *copy, *p, *start, *end;
547 struct map_value *v;
548
549 if (string == 0 || string[0] == 0)
550 return string;
551
552 file_location loc = get_md_ptr_loc (ptr: string)->loc;
553 base = p = copy = ASTRDUP (string);
554 while ((start = strchr (s: p, c: '<')) && (end = strchr (s: start, c: '>')))
555 {
556 p = start + 1;
557
558 *end = 0;
559 v = map_attr_string (loc, p);
560 *end = '>';
561 if (v == 0)
562 continue;
563
564 /* Add everything between the last copied byte and the '<',
565 then add in the attribute value. */
566 obstack_grow (&m_string_obstack, base, start - base);
567 obstack_grow (&m_string_obstack, v->string, strlen (v->string));
568 base = end + 1;
569 }
570 if (base != copy)
571 {
572 obstack_grow (&m_string_obstack, base, strlen (base) + 1);
573 copy = XOBFINISH (&m_string_obstack, char *);
574 copy_md_ptr_loc (new_ptr: copy, old_ptr: string);
575 return copy;
576 }
577 return string;
578}
579
580/* Return a deep copy of X, substituting the current iterator
581 values into any strings. */
582
583rtx
584md_reader::copy_rtx_for_iterators (rtx original)
585{
586 const char *format_ptr, *p;
587 int i, j;
588 rtx x;
589
590 if (original == 0)
591 return original;
592
593 /* Create a shallow copy of ORIGINAL. */
594 x = rtx_alloc (GET_CODE (original));
595 memcpy (dest: x, src: original, RTX_CODE_SIZE (GET_CODE (original)));
596
597 /* Change each string and recursively change each rtx. */
598 format_ptr = GET_RTX_FORMAT (GET_CODE (original));
599 for (i = 0; format_ptr[i] != 0; i++)
600 switch (format_ptr[i])
601 {
602 case 'T':
603 while (XTMPL (x, i) != (p = apply_iterator_to_string (XTMPL (x, i))))
604 XTMPL (x, i) = p;
605 break;
606
607 case 'S':
608 case 's':
609 while (XSTR (x, i) != (p = apply_iterator_to_string (XSTR (x, i))))
610 XSTR (x, i) = p;
611 break;
612
613 case 'e':
614 XEXP (x, i) = copy_rtx_for_iterators (XEXP (x, i));
615 break;
616
617 case 'V':
618 case 'E':
619 if (XVEC (original, i))
620 {
621 XVEC (x, i) = rtvec_alloc (XVECLEN (original, i));
622 for (j = 0; j < XVECLEN (x, i); j++)
623 XVECEXP (x, i, j)
624 = copy_rtx_for_iterators (XVECEXP (original, i, j));
625 }
626 break;
627
628 default:
629 break;
630 }
631 return x;
632}
633
634#ifdef GENERATOR_FILE
635
636/* Return a condition that must satisfy both ORIGINAL and EXTRA. If ORIGINAL
637 has the form "&& ..." (as used in define_insn_and_splits), assume that
638 EXTRA is already satisfied. Empty strings are treated like "true". */
639
640static const char *
641add_condition_to_string (const char *original, const char *extra)
642{
643 if (original != 0 && original[0] == '&' && original[1] == '&')
644 return original;
645 return rtx_reader_ptr->join_c_conditions (cond1: original, cond2: extra);
646}
647
648/* Like add_condition, but applied to all conditions in rtx X. */
649
650static void
651add_condition_to_rtx (rtx x, const char *extra)
652{
653 switch (GET_CODE (x))
654 {
655 case DEFINE_INSN:
656 case DEFINE_EXPAND:
657 case DEFINE_SUBST:
658 XSTR (x, 2) = add_condition_to_string (XSTR (x, 2), extra);
659 break;
660
661 case DEFINE_SPLIT:
662 case DEFINE_PEEPHOLE:
663 case DEFINE_PEEPHOLE2:
664 case DEFINE_COND_EXEC:
665 XSTR (x, 1) = add_condition_to_string (XSTR (x, 1), extra);
666 break;
667
668 case DEFINE_INSN_AND_SPLIT:
669 case DEFINE_INSN_AND_REWRITE:
670 XSTR (x, 2) = add_condition_to_string (XSTR (x, 2), extra);
671 XSTR (x, 4) = add_condition_to_string (XSTR (x, 4), extra);
672 break;
673
674 default:
675 break;
676 }
677}
678
679/* Apply the current iterator values to all attribute_uses. */
680
681static void
682apply_attribute_uses (void)
683{
684 struct map_value *v;
685 attribute_use *ause;
686 unsigned int i;
687
688 FOR_EACH_VEC_ELT (attribute_uses, i, ause)
689 {
690 v = map_attr_string (loc: ause->loc, p: ause->value);
691 if (!v)
692 fatal_with_file_and_line ("unknown iterator value `%s'", ause->value);
693 ause->group->apply_iterator (ause->x, ause->index,
694 ause->group->find_builtin (v->string));
695 }
696}
697
698/* A htab_traverse callback for iterators. Add all used iterators
699 to current_iterators. */
700
701static int
702add_current_iterators (void **slot, void *data ATTRIBUTE_UNUSED)
703{
704 struct mapping *iterator;
705
706 iterator = (struct mapping *) *slot;
707 if (iterator->current_value)
708 current_iterators.safe_push (obj: iterator);
709 return 1;
710}
711
712/* Return a hash value for overloaded_name UNCAST_ONAME. There shouldn't
713 be many instances of two overloaded_names having the same name but
714 different arguments, so hashing on the name should be good enough in
715 practice. */
716
717static hashval_t
718overloaded_name_hash (const void *uncast_oname)
719{
720 const overloaded_name *oname = (const overloaded_name *) uncast_oname;
721 return htab_hash_string (oname->name);
722}
723
724/* Return true if two overloaded_names are similar enough to share
725 the same generated functions. */
726
727static int
728overloaded_name_eq_p (const void *uncast_oname1, const void *uncast_oname2)
729{
730 const overloaded_name *oname1 = (const overloaded_name *) uncast_oname1;
731 const overloaded_name *oname2 = (const overloaded_name *) uncast_oname2;
732 if (strcmp (s1: oname1->name, s2: oname2->name) != 0
733 || oname1->arg_types.length () != oname2->arg_types.length ())
734 return 0;
735
736 for (unsigned int i = 0; i < oname1->arg_types.length (); ++i)
737 if (strcmp (s1: oname1->arg_types[i], s2: oname2->arg_types[i]) != 0)
738 return 0;
739
740 return 1;
741}
742
743/* Return true if X has an instruction name in XSTR (X, 0). */
744
745static bool
746named_rtx_p (rtx x)
747{
748 switch (GET_CODE (x))
749 {
750 case DEFINE_EXPAND:
751 case DEFINE_INSN:
752 case DEFINE_INSN_AND_SPLIT:
753 case DEFINE_INSN_AND_REWRITE:
754 return true;
755
756 default:
757 return false;
758 }
759}
760
761/* Check whether ORIGINAL is a named pattern whose name starts with '@'.
762 If so, return the associated overloaded_name and add the iterator for
763 each argument to ITERATORS. Return null otherwise. */
764
765overloaded_name *
766md_reader::handle_overloaded_name (rtx original, vec<mapping *> *iterators)
767{
768 /* Check for the leading '@'. */
769 if (!named_rtx_p (x: original) || XSTR (original, 0)[0] != '@')
770 return NULL;
771
772 /* Remove the '@', so that no other code needs to worry about it. */
773 const char *name = XSTR (original, 0);
774 file_location loc = get_md_ptr_loc (ptr: name)->loc;
775 copy_md_ptr_loc (new_ptr: name + 1, old_ptr: name);
776 name += 1;
777 XSTR (original, 0) = name;
778
779 /* Build a copy of the name without the '<...>' attribute strings.
780 Add the iterator associated with each such attribute string to ITERATORS
781 and add an associated argument to TMP_ONAME. */
782 char *copy = ASTRDUP (name);
783 char *base = copy, *start, *end;
784 overloaded_name tmp_oname;
785 tmp_oname.arg_types.create (nelems: current_iterators.length ());
786 bool pending_underscore_p = false;
787 while ((start = strchr (s: base, c: '<')) && (end = strchr (s: start, c: '>')))
788 {
789 *end = 0;
790 mapping *iterator;
791 if (!map_attr_string (loc, p: start + 1, iterator_out: &iterator))
792 fatal_with_file_and_line ("unknown iterator `%s'", start + 1);
793 *end = '>';
794
795 /* Remove a trailing underscore, so that we don't end a name
796 with "_" or turn "_<...>_" into "__". */
797 if (start != base && start[-1] == '_')
798 {
799 start -= 1;
800 pending_underscore_p = true;
801 }
802
803 /* Add the text between either the last '>' or the start of
804 the string and this '<'. */
805 obstack_grow (&m_string_obstack, base, start - base);
806 base = end + 1;
807
808 /* If there's a character we need to keep after the '>', check
809 whether we should prefix it with a previously-dropped '_'. */
810 if (base[0] != 0 && base[0] != '<')
811 {
812 if (pending_underscore_p && base[0] != '_')
813 obstack_1grow (&m_string_obstack, '_');
814 pending_underscore_p = false;
815 }
816
817 /* Skip define_subst iterators, since define_substs are allowed to
818 add new match_operands in their output templates. */
819 if (iterator->group != &substs)
820 {
821 /* Record an argument for ITERATOR. */
822 iterators->safe_push (obj: iterator);
823 tmp_oname.arg_types.safe_push (obj: iterator->group->type);
824 }
825 }
826 if (base == copy)
827 fatal_with_file_and_line ("no iterator attributes in name `%s'", name);
828
829 size_t length = obstack_object_size (&m_string_obstack);
830 if (length == 0)
831 fatal_with_file_and_line ("`%s' only contains iterator attributes", name);
832
833 /* Get the completed name. */
834 obstack_grow (&m_string_obstack, base, strlen (base) + 1);
835 char *new_name = XOBFINISH (&m_string_obstack, char *);
836 tmp_oname.name = new_name;
837
838 if (!m_overloads_htab)
839 m_overloads_htab = htab_create (31, overloaded_name_hash,
840 overloaded_name_eq_p, NULL);
841
842 /* See whether another pattern had the same overload name and list
843 of argument types. Create a new permanent one if not. */
844 void **slot = htab_find_slot (m_overloads_htab, &tmp_oname, INSERT);
845 overloaded_name *oname = (overloaded_name *) *slot;
846 if (!oname)
847 {
848 *slot = oname = new overloaded_name;
849 oname->name = tmp_oname.name;
850 oname->arg_types = tmp_oname.arg_types;
851 oname->next = NULL;
852 oname->first_instance = NULL;
853 oname->next_instance_ptr = &oname->first_instance;
854
855 *m_next_overload_ptr = oname;
856 m_next_overload_ptr = &oname->next;
857 }
858 else
859 {
860 obstack_free (&m_string_obstack, new_name);
861 tmp_oname.arg_types.release ();
862 }
863
864 return oname;
865}
866
867/* Add an instance of ONAME for instruction pattern X. ITERATORS[I]
868 gives the iterator associated with argument I of ONAME. */
869
870static void
871add_overload_instance (overloaded_name *oname, const vec<mapping *> &iterators, rtx x)
872{
873 /* Create the instance. */
874 overloaded_instance *instance = new overloaded_instance;
875 instance->next = NULL;
876 instance->arg_values.create (nelems: oname->arg_types.length ());
877 for (unsigned int i = 0; i < iterators.length (); ++i)
878 {
879 int value = iterators[i]->current_value->number;
880 const char *name = iterators[i]->group->get_c_token (value);
881 instance->arg_values.quick_push (obj: name);
882 }
883 instance->name = XSTR (x, 0);
884 instance->insn = x;
885
886 /* Chain it onto the end of ONAME's list. */
887 *oname->next_instance_ptr = instance;
888 oname->next_instance_ptr = &instance->next;
889}
890
891/* Expand all iterators in the current rtx, which is given as ORIGINAL.
892 Build a list of expanded rtxes in the EXPR_LIST pointed to by QUEUE. */
893
894static void
895apply_iterators (rtx original, vec<rtx> *queue)
896{
897 unsigned int i;
898 const char *condition;
899 iterator_use *iuse;
900 struct mapping *iterator;
901 struct map_value *v;
902 rtx x;
903
904 if (iterator_uses.is_empty ())
905 {
906 /* Raise an error if any attributes were used. */
907 apply_attribute_uses ();
908
909 if (named_rtx_p (x: original) && XSTR (original, 0)[0] == '@')
910 fatal_with_file_and_line ("'@' used without iterators");
911
912 queue->safe_push (obj: original);
913 return;
914 }
915
916 /* Clear out the iterators from the previous run. */
917 FOR_EACH_VEC_ELT (current_iterators, i, iterator)
918 iterator->current_value = NULL;
919 current_iterators.truncate (size: 0);
920
921 /* Mark the iterators that we need this time. */
922 FOR_EACH_VEC_ELT (iterator_uses, i, iuse)
923 iuse->iterator->current_value = iuse->iterator->values;
924
925 /* Get the list of iterators that are in use, preserving the
926 definition order within each group. */
927 htab_traverse (modes.iterators, add_current_iterators, NULL);
928 htab_traverse (codes.iterators, add_current_iterators, NULL);
929 htab_traverse (ints.iterators, add_current_iterators, NULL);
930 htab_traverse (substs.iterators, add_current_iterators, NULL);
931 gcc_assert (!current_iterators.is_empty ());
932
933 /* Check whether this is a '@' overloaded pattern. */
934 auto_vec<mapping *, 16> iterators;
935 overloaded_name *oname
936 = rtx_reader_ptr->handle_overloaded_name (original, iterators: &iterators);
937
938 for (;;)
939 {
940 /* Apply the current iterator values. Accumulate a condition to
941 say when the resulting rtx can be used. */
942 condition = "";
943 FOR_EACH_VEC_ELT (iterator_uses, i, iuse)
944 {
945 if (iuse->iterator->group == &substs)
946 continue;
947 v = iuse->iterator->current_value;
948 iuse->iterator->group->apply_iterator (iuse->x, iuse->index,
949 v->number);
950 condition = rtx_reader_ptr->join_c_conditions (cond1: condition, cond2: v->string);
951 }
952 apply_attribute_uses ();
953 x = rtx_reader_ptr->copy_rtx_for_iterators (original);
954 add_condition_to_rtx (x, extra: condition);
955
956 /* We apply subst iterator after RTL-template is copied, as during
957 subst-iterator processing, we could add an attribute to the
958 RTL-template, and we don't want to do it in the original one. */
959 bool add_oname = true;
960 FOR_EACH_VEC_ELT (iterator_uses, i, iuse)
961 {
962 v = iuse->iterator->current_value;
963 if (iuse->iterator->group == &substs)
964 {
965 iuse->x = x;
966 iuse->index = 0;
967 current_iterator_name = iuse->iterator->name;
968 iuse->iterator->group->apply_iterator (iuse->x, iuse->index,
969 v->number);
970 /* Only handle '@' overloading for the default value.
971 See handle_overloaded_name for details. */
972 if (v != iuse->iterator->values)
973 add_oname = false;
974 }
975 }
976
977 if (oname && add_oname)
978 add_overload_instance (oname, iterators, x);
979
980 /* Add the new rtx to the end of the queue. */
981 queue->safe_push (obj: x);
982
983 /* Lexicographically increment the iterator value sequence.
984 That is, cycle through iterator values, starting from the right,
985 and stopping when one of them doesn't wrap around. */
986 i = current_iterators.length ();
987 for (;;)
988 {
989 if (i == 0)
990 return;
991 i--;
992 iterator = current_iterators[i];
993 iterator->current_value = iterator->current_value->next;
994 if (iterator->current_value)
995 break;
996 iterator->current_value = iterator->values;
997 }
998 }
999}
1000#endif /* #ifdef GENERATOR_FILE */
1001
1002/* Add a new "mapping" structure to hashtable TABLE. NAME is the name
1003 of the mapping and GROUP is the group to which it belongs. */
1004
1005static struct mapping *
1006add_mapping (struct iterator_group *group, htab_t table, const char *name)
1007{
1008 struct mapping *m;
1009 void **slot;
1010
1011 m = XNEW (struct mapping);
1012 m->name = xstrdup (name);
1013 m->group = group;
1014 m->values = 0;
1015 m->current_value = NULL;
1016
1017 slot = htab_find_slot (table, m, INSERT);
1018 if (*slot != 0)
1019 fatal_with_file_and_line ("`%s' already defined", name);
1020
1021 *slot = m;
1022 return m;
1023}
1024
1025/* Add the pair (NUMBER, STRING) to a list of map_value structures.
1026 END_PTR points to the current null terminator for the list; return
1027 a pointer the new null terminator. */
1028
1029static struct map_value **
1030add_map_value (struct map_value **end_ptr, int number, const char *string)
1031{
1032 struct map_value *value;
1033
1034 value = XNEW (struct map_value);
1035 value->next = 0;
1036 value->number = number;
1037 value->string = string;
1038
1039 *end_ptr = value;
1040 return &value->next;
1041}
1042
1043/* Do one-time initialization of the mode and code attributes. */
1044
1045static void
1046initialize_iterators (void)
1047{
1048 struct mapping *lower, *upper;
1049 struct map_value **lower_ptr, **upper_ptr;
1050 char *copy, *p;
1051 int i;
1052
1053 modes.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0);
1054 modes.iterators = htab_create (13, leading_string_hash,
1055 leading_string_eq_p, 0);
1056 modes.type = "machine_mode";
1057 modes.find_builtin = find_mode;
1058 modes.apply_iterator = apply_mode_iterator;
1059 modes.get_c_token = get_mode_token;
1060
1061 codes.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0);
1062 codes.iterators = htab_create (13, leading_string_hash,
1063 leading_string_eq_p, 0);
1064 codes.type = "rtx_code";
1065 codes.find_builtin = find_code;
1066 codes.apply_iterator = apply_code_iterator;
1067 codes.get_c_token = get_code_token;
1068
1069 ints.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0);
1070 ints.iterators = htab_create (13, leading_string_hash,
1071 leading_string_eq_p, 0);
1072 ints.type = "int";
1073 ints.find_builtin = find_int;
1074 ints.apply_iterator = apply_int_iterator;
1075 ints.get_c_token = get_int_token;
1076 ints.has_self_attr = true;
1077
1078 substs.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0);
1079 substs.iterators = htab_create (13, leading_string_hash,
1080 leading_string_eq_p, 0);
1081 substs.type = "int";
1082 substs.find_builtin = find_int; /* We don't use it, anyway. */
1083#ifdef GENERATOR_FILE
1084 substs.apply_iterator = apply_subst_iterator;
1085#endif
1086 substs.get_c_token = get_int_token;
1087
1088 lower = add_mapping (group: &modes, table: modes.attrs, name: "mode");
1089 upper = add_mapping (group: &modes, table: modes.attrs, name: "MODE");
1090 lower_ptr = &lower->values;
1091 upper_ptr = &upper->values;
1092 for (i = 0; i < MAX_MACHINE_MODE; i++)
1093 {
1094 copy = xstrdup (GET_MODE_NAME (i));
1095 for (p = copy; *p != 0; p++)
1096 *p = TOLOWER (*p);
1097
1098 upper_ptr = add_map_value (end_ptr: upper_ptr, number: i, GET_MODE_NAME (i));
1099 lower_ptr = add_map_value (end_ptr: lower_ptr, number: i, string: copy);
1100 }
1101
1102 lower = add_mapping (group: &codes, table: codes.attrs, name: "code");
1103 upper = add_mapping (group: &codes, table: codes.attrs, name: "CODE");
1104 lower_ptr = &lower->values;
1105 upper_ptr = &upper->values;
1106 for (i = 0; i < NUM_RTX_CODE; i++)
1107 {
1108 copy = xstrdup (GET_RTX_NAME (i));
1109 for (p = copy; *p != 0; p++)
1110 *p = TOUPPER (*p);
1111
1112 lower_ptr = add_map_value (end_ptr: lower_ptr, number: i, GET_RTX_NAME (i));
1113 upper_ptr = add_map_value (end_ptr: upper_ptr, number: i, string: copy);
1114 }
1115}
1116
1117
1118#ifdef GENERATOR_FILE
1119/* Process a define_conditions directive, starting with the optional
1120 space after the "define_conditions". The directive looks like this:
1121
1122 (define_conditions [
1123 (number "string")
1124 (number "string")
1125 ...
1126 ])
1127
1128 It's not intended to appear in machine descriptions. It is
1129 generated by (the program generated by) genconditions.cc, and
1130 slipped in at the beginning of the sequence of MD files read by
1131 most of the other generators. */
1132void
1133md_reader::read_conditions ()
1134{
1135 int c;
1136
1137 require_char_ws (expected: '[');
1138
1139 while ( (c = read_skip_spaces ()) != ']')
1140 {
1141 struct md_name name;
1142 char *expr;
1143 int value;
1144
1145 if (c != '(')
1146 fatal_expected_char ('(', c);
1147
1148 read_name (name: &name);
1149 validate_const_int (name.string);
1150 value = atoi (nptr: name.string);
1151
1152 require_char_ws (expected: '"');
1153 expr = read_quoted_string ();
1154
1155 require_char_ws (expected: ')');
1156
1157 add_c_test (expr, value);
1158 }
1159}
1160#endif /* #ifdef GENERATOR_FILE */
1161
1162static void
1163validate_const_int (const char *string)
1164{
1165 const char *cp;
1166 int valid = 1;
1167
1168 cp = string;
1169 while (*cp && ISSPACE (*cp))
1170 cp++;
1171 if (*cp == '-' || *cp == '+')
1172 cp++;
1173 if (*cp == 0)
1174 valid = 0;
1175 for (; *cp; cp++)
1176 if (! ISDIGIT (*cp))
1177 {
1178 valid = 0;
1179 break;
1180 }
1181 if (!valid)
1182 fatal_with_file_and_line ("invalid decimal constant \"%s\"\n", string);
1183}
1184
1185static void
1186validate_const_wide_int (const char *string)
1187{
1188 const char *cp;
1189 int valid = 1;
1190
1191 cp = string;
1192 while (*cp && ISSPACE (*cp))
1193 cp++;
1194 /* Skip the leading 0x. */
1195 if (cp[0] == '0' || cp[1] == 'x')
1196 cp += 2;
1197 else
1198 valid = 0;
1199 if (*cp == 0)
1200 valid = 0;
1201 for (; *cp; cp++)
1202 if (! ISXDIGIT (*cp))
1203 valid = 0;
1204 if (!valid)
1205 fatal_with_file_and_line ("invalid hex constant \"%s\"\n", string);
1206}
1207
1208/* Record that X uses iterator ITERATOR. If the use is in an operand
1209 of X, INDEX is the index of that operand, otherwise it is ignored. */
1210
1211static void
1212record_iterator_use (struct mapping *iterator, rtx x, unsigned int index)
1213{
1214 struct iterator_use iuse = {.iterator: iterator, .x: x, .index: index};
1215 iterator_uses.safe_push (obj: iuse);
1216}
1217
1218/* Record that X uses attribute VALUE at location LOC, where VALUE must
1219 match a built-in value from group GROUP. If the use is in an operand
1220 of X, INDEX is the index of that operand, otherwise it is ignored. */
1221
1222static void
1223record_attribute_use (struct iterator_group *group, file_location loc, rtx x,
1224 unsigned int index, const char *value)
1225{
1226 struct attribute_use ause = {.group: group, .loc: loc, .value: value, .x: x, .index: index};
1227 attribute_uses.safe_push (obj: ause);
1228}
1229
1230/* Interpret NAME as either a built-in value, iterator or attribute
1231 for group GROUP. X and INDEX are the values to pass to GROUP's
1232 apply_iterator callback. LOC is the location of the use. */
1233
1234void
1235md_reader::record_potential_iterator_use (struct iterator_group *group,
1236 file_location loc,
1237 rtx x, unsigned int index,
1238 const char *name)
1239{
1240 struct mapping *m;
1241 size_t len;
1242
1243 len = strlen (s: name);
1244 if (name[0] == '<' && name[len - 1] == '>')
1245 {
1246 /* Copy the attribute string into permanent storage, without the
1247 angle brackets around it. */
1248 obstack_grow0 (&m_string_obstack, name + 1, len - 2);
1249 record_attribute_use (group, loc, x, index,
1250 XOBFINISH (&m_string_obstack, char *));
1251 }
1252 else
1253 {
1254 m = (struct mapping *) htab_find (group->iterators, &name);
1255 if (m != 0)
1256 record_iterator_use (iterator: m, x, index);
1257 else
1258 group->apply_iterator (x, index, group->find_builtin (name));
1259 }
1260}
1261
1262#ifdef GENERATOR_FILE
1263
1264/* Finish reading a declaration of the form:
1265
1266 (define... <name> [<value1> ... <valuen>])
1267
1268 from the MD file, where each <valuei> is either a bare symbol name or a
1269 "(<name> <string>)" pair. The "(define..." part has already been read.
1270
1271 Represent the declaration as a "mapping" structure; add it to TABLE
1272 (which belongs to GROUP) and return it. */
1273
1274struct mapping *
1275md_reader::read_mapping (struct iterator_group *group, htab_t table)
1276{
1277 struct md_name name;
1278 struct mapping *m;
1279 struct map_value **end_ptr;
1280 const char *string;
1281 int number, c;
1282
1283 /* Read the mapping name and create a structure for it. */
1284 read_name (name: &name);
1285 m = add_mapping (group, table, name: name.string);
1286
1287 require_char_ws (expected: '[');
1288
1289 /* Read each value. */
1290 end_ptr = &m->values;
1291 c = read_skip_spaces ();
1292 do
1293 {
1294 if (c != '(')
1295 {
1296 /* A bare symbol name that is implicitly paired to an
1297 empty string. */
1298 unread_char (ch: c);
1299 read_name (name: &name);
1300 string = "";
1301 }
1302 else
1303 {
1304 /* A "(name string)" pair. */
1305 read_name (name: &name);
1306 string = read_string (star_if_braced: false);
1307 require_char_ws (expected: ')');
1308 }
1309 auto *subm = (struct mapping *) htab_find (group->iterators,
1310 &name.string);
1311 if (subm)
1312 {
1313 if (m == subm)
1314 fatal_with_file_and_line ("recursive definition of `%s'",
1315 name.string);
1316 for (map_value *v = subm->values; v; v = v->next)
1317 {
1318 auto *joined = rtx_reader_ptr->join_c_conditions (cond1: v->string,
1319 cond2: string);
1320 end_ptr = add_map_value (end_ptr, number: v->number, string: joined);
1321 }
1322 }
1323 else
1324 {
1325 number = group->find_builtin (name.string);
1326 end_ptr = add_map_value (end_ptr, number, string);
1327 }
1328 c = read_skip_spaces ();
1329 }
1330 while (c != ']');
1331
1332 return m;
1333}
1334
1335/* For iterator with name ATTR_NAME generate define_attr with values
1336 'yes' and 'no'. This attribute is used to mark templates to which
1337 define_subst ATTR_NAME should be applied. This attribute is set and
1338 defined implicitly and automatically. */
1339static void
1340add_define_attr_for_define_subst (const char *attr_name, vec<rtx> *queue)
1341{
1342 rtx const_str, return_rtx;
1343
1344 return_rtx = rtx_alloc (DEFINE_ATTR);
1345 PUT_CODE (return_rtx, DEFINE_ATTR);
1346
1347 const_str = rtx_alloc (CONST_STRING);
1348 PUT_CODE (const_str, CONST_STRING);
1349 XSTR (const_str, 0) = xstrdup ("no");
1350
1351 XSTR (return_rtx, 0) = xstrdup (attr_name);
1352 XSTR (return_rtx, 1) = xstrdup ("no,yes");
1353 XEXP (return_rtx, 2) = const_str;
1354
1355 queue->safe_push (obj: return_rtx);
1356}
1357
1358/* This routine generates DEFINE_SUBST_ATTR expression with operands
1359 ATTR_OPERANDS and places it to QUEUE. */
1360static void
1361add_define_subst_attr (const char **attr_operands, vec<rtx> *queue)
1362{
1363 rtx return_rtx;
1364 int i;
1365
1366 return_rtx = rtx_alloc (DEFINE_SUBST_ATTR);
1367 PUT_CODE (return_rtx, DEFINE_SUBST_ATTR);
1368
1369 for (i = 0; i < 4; i++)
1370 XSTR (return_rtx, i) = xstrdup (attr_operands[i]);
1371
1372 queue->safe_push (obj: return_rtx);
1373}
1374
1375/* Read define_subst_attribute construction. It has next form:
1376 (define_subst_attribute <attribute_name> <iterator_name> <value1> <value2>)
1377 Attribute is substituted with value1 when no subst is applied and with
1378 value2 in the opposite case.
1379 Attributes are added to SUBST_ATTRS_TABLE.
1380 In case the iterator is encountered for the first time, it's added to
1381 SUBST_ITERS_TABLE. Also, implicit define_attr is generated. */
1382
1383static void
1384read_subst_mapping (htab_t subst_iters_table, htab_t subst_attrs_table,
1385 vec<rtx> *queue)
1386{
1387 struct mapping *m;
1388 struct map_value **end_ptr;
1389 const char *attr_operands[4];
1390 int i;
1391
1392 for (i = 0; i < 4; i++)
1393 attr_operands[i] = rtx_reader_ptr->read_string (star_if_braced: false);
1394
1395 add_define_subst_attr (attr_operands, queue);
1396
1397 bind_subst_iter_and_attr (iter: attr_operands[1], attr: attr_operands[0]);
1398
1399 m = (struct mapping *) htab_find (substs.iterators, &attr_operands[1]);
1400 if (!m)
1401 {
1402 m = add_mapping (group: &substs, table: subst_iters_table, name: attr_operands[1]);
1403 end_ptr = &m->values;
1404 end_ptr = add_map_value (end_ptr, number: 1, string: "");
1405 add_map_value (end_ptr, number: 2, string: "");
1406
1407 add_define_attr_for_define_subst (attr_name: attr_operands[1], queue);
1408 }
1409
1410 m = add_mapping (group: &substs, table: subst_attrs_table, name: attr_operands[0]);
1411 end_ptr = &m->values;
1412 end_ptr = add_map_value (end_ptr, number: 1, string: attr_operands[2]);
1413 add_map_value (end_ptr, number: 2, string: attr_operands[3]);
1414}
1415
1416/* Check newly-created code iterator ITERATOR to see whether every code has the
1417 same format. */
1418
1419static void
1420check_code_iterator (struct mapping *iterator)
1421{
1422 struct map_value *v;
1423 enum rtx_code bellwether;
1424
1425 bellwether = (enum rtx_code) iterator->values->number;
1426 for (v = iterator->values->next; v != 0; v = v->next)
1427 if (strcmp (GET_RTX_FORMAT (bellwether), GET_RTX_FORMAT (v->number)) != 0)
1428 fatal_with_file_and_line ("code iterator `%s' combines "
1429 "`%s' and `%s', which have different "
1430 "rtx formats", iterator->name,
1431 GET_RTX_NAME (bellwether),
1432 GET_RTX_NAME (v->number));
1433}
1434
1435/* Check that all values of attribute ATTR are rtx codes that have a
1436 consistent format. Return a representative code. */
1437
1438static rtx_code
1439check_attribute_codes (mapping *attr)
1440{
1441 rtx_code bellwether = UNKNOWN;
1442 for (map_value *v = attr->values; v != 0; v = v->next)
1443 {
1444 rtx_code code = maybe_find_code (name: v->string);
1445 if (code == UNKNOWN)
1446 fatal_with_file_and_line ("attribute `%s' contains "
1447 "unrecognized rtx code `%s'",
1448 attr->name, v->string);
1449 if (bellwether == UNKNOWN)
1450 bellwether = code;
1451 else if (strcmp (GET_RTX_FORMAT (bellwether),
1452 GET_RTX_FORMAT (code)) != 0)
1453 fatal_with_file_and_line ("attribute `%s' combines "
1454 "`%s' and `%s', which have different "
1455 "rtx formats", attr->name,
1456 GET_RTX_NAME (bellwether),
1457 GET_RTX_NAME (code));
1458 }
1459 return bellwether;
1460}
1461
1462/* Read an rtx-related declaration from the MD file, given that it
1463 starts with directive name RTX_NAME. Return true if it expands to
1464 one or more rtxes (as defined by rtx.def). When returning true,
1465 store the list of rtxes as an EXPR_LIST in *X. */
1466
1467bool
1468rtx_reader::read_rtx (const char *rtx_name, vec<rtx> *rtxen)
1469{
1470 /* Handle various rtx-related declarations that aren't themselves
1471 encoded as rtxes. */
1472 if (strcmp (s1: rtx_name, s2: "define_conditions") == 0)
1473 {
1474 read_conditions ();
1475 return false;
1476 }
1477 if (strcmp (s1: rtx_name, s2: "define_mode_attr") == 0)
1478 {
1479 read_mapping (group: &modes, table: modes.attrs);
1480 return false;
1481 }
1482 if (strcmp (s1: rtx_name, s2: "define_mode_iterator") == 0)
1483 {
1484 read_mapping (group: &modes, table: modes.iterators);
1485 return false;
1486 }
1487 if (strcmp (s1: rtx_name, s2: "define_code_attr") == 0)
1488 {
1489 read_mapping (group: &codes, table: codes.attrs);
1490 return false;
1491 }
1492 if (strcmp (s1: rtx_name, s2: "define_code_iterator") == 0)
1493 {
1494 check_code_iterator (iterator: read_mapping (group: &codes, table: codes.iterators));
1495 return false;
1496 }
1497 if (strcmp (s1: rtx_name, s2: "define_int_attr") == 0)
1498 {
1499 read_mapping (group: &ints, table: ints.attrs);
1500 return false;
1501 }
1502 if (strcmp (s1: rtx_name, s2: "define_int_iterator") == 0)
1503 {
1504 read_mapping (group: &ints, table: ints.iterators);
1505 return false;
1506 }
1507 if (strcmp (s1: rtx_name, s2: "define_subst_attr") == 0)
1508 {
1509 read_subst_mapping (subst_iters_table: substs.iterators, subst_attrs_table: substs.attrs, queue: rtxen);
1510
1511 /* READ_SUBST_MAPPING could generate a new DEFINE_ATTR. Return
1512 TRUE to process it. */
1513 return true;
1514 }
1515
1516 apply_iterators (original: rtx_reader_ptr->read_rtx_code (code_name: rtx_name), queue: rtxen);
1517 iterator_uses.truncate (size: 0);
1518 attribute_uses.truncate (size: 0);
1519
1520 return true;
1521}
1522
1523#endif /* #ifdef GENERATOR_FILE */
1524
1525/* Do one-time initialization. */
1526
1527static void
1528one_time_initialization (void)
1529{
1530 static bool initialized = false;
1531
1532 if (!initialized)
1533 {
1534 initialize_iterators ();
1535 initialized = true;
1536 }
1537}
1538
1539/* Consume characters until encountering a character in TERMINATOR_CHARS,
1540 consuming the terminator character if CONSUME_TERMINATOR is true.
1541 Return all characters before the terminator as an allocated buffer. */
1542
1543char *
1544rtx_reader::read_until (const char *terminator_chars, bool consume_terminator)
1545{
1546 int ch = read_skip_spaces ();
1547 unread_char (ch);
1548 auto_vec<char> buf;
1549 while (1)
1550 {
1551 ch = read_char ();
1552 if (strchr (s: terminator_chars, c: ch))
1553 {
1554 if (!consume_terminator)
1555 unread_char (ch);
1556 break;
1557 }
1558 buf.safe_push (obj: ch);
1559 }
1560 buf.safe_push (obj: '\0');
1561 return xstrdup (buf.address ());
1562}
1563
1564/* Subroutine of read_rtx_code, for parsing zero or more flags. */
1565
1566static void
1567read_flags (rtx return_rtx)
1568{
1569 while (1)
1570 {
1571 int ch = read_char ();
1572 if (ch != '/')
1573 {
1574 unread_char (ch);
1575 break;
1576 }
1577
1578 int flag_char = read_char ();
1579 switch (flag_char)
1580 {
1581 case 's':
1582 RTX_FLAG (return_rtx, in_struct) = 1;
1583 break;
1584 case 'v':
1585 RTX_FLAG (return_rtx, volatil) = 1;
1586 break;
1587 case 'u':
1588 RTX_FLAG (return_rtx, unchanging) = 1;
1589 break;
1590 case 'f':
1591 RTX_FLAG (return_rtx, frame_related) = 1;
1592 break;
1593 case 'j':
1594 RTX_FLAG (return_rtx, jump) = 1;
1595 break;
1596 case 'c':
1597 RTX_FLAG (return_rtx, call) = 1;
1598 break;
1599 case 'i':
1600 RTX_FLAG (return_rtx, return_val) = 1;
1601 break;
1602 default:
1603 fatal_with_file_and_line ("unrecognized flag: `%c'", flag_char);
1604 }
1605 }
1606}
1607
1608/* Return the numeric value n for GET_REG_NOTE_NAME (n) for STRING,
1609 or fail if STRING isn't recognized. */
1610
1611static int
1612parse_reg_note_name (const char *string)
1613{
1614 for (int i = 0; i < REG_NOTE_MAX; i++)
1615 if (strcmp (s1: string, GET_REG_NOTE_NAME (i)) == 0)
1616 return i;
1617 fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string);
1618}
1619
1620/* Allocate an rtx for code NAME. If NAME is a code iterator or an
1621 attribute, record its use for later and use one of its possible
1622 values as an interim rtx code. */
1623
1624rtx
1625rtx_reader::rtx_alloc_for_name (const char *name)
1626{
1627#ifdef GENERATOR_FILE
1628 size_t len = strlen (s: name);
1629 if (name[0] == '<' && name[len - 1] == '>')
1630 {
1631 /* Copy the attribute string into permanent storage, without the
1632 angle brackets around it. */
1633 obstack *strings = get_string_obstack ();
1634 obstack_grow0 (strings, name + 1, len - 2);
1635 char *deferred_name = XOBFINISH (strings, char *);
1636
1637 /* Find the name of the attribute. */
1638 const char *attr = strchr (s: deferred_name, c: ':');
1639 if (!attr)
1640 attr = deferred_name;
1641
1642 /* Find the attribute itself. */
1643 mapping *m = nullptr;
1644 for (auto attrs : { codes.attrs, ints.attrs, modes.attrs })
1645 if (auto *newm = (mapping *) htab_find (attrs, &attr))
1646 {
1647 if (m)
1648 fatal_with_file_and_line ("ambiguous attribute `%s`", attr);
1649 m = newm;
1650 }
1651 if (!m)
1652 fatal_with_file_and_line ("unknown attribute `%s'", attr);
1653
1654 /* Pick the first possible code for now, and record the attribute
1655 use for later. */
1656 rtx x = rtx_alloc (check_attribute_codes (attr: m));
1657 record_attribute_use (group: &codes, loc: get_current_location (),
1658 x, index: 0, value: deferred_name);
1659 return x;
1660 }
1661
1662 mapping *iterator = (mapping *) htab_find (codes.iterators, &name);
1663 if (iterator != 0)
1664 {
1665 /* Pick the first possible code for now, and record the iterator
1666 use for later. */
1667 rtx x = rtx_alloc (rtx_code (iterator->values->number));
1668 record_iterator_use (iterator, x, index: 0);
1669 return x;
1670 }
1671#endif
1672
1673 return rtx_alloc (rtx_code (codes.find_builtin (name)));
1674}
1675
1676/* Subroutine of read_rtx and read_nested_rtx. CODE_NAME is the name of
1677 either an rtx code or a code iterator. Parse the rest of the rtx and
1678 return it. */
1679
1680rtx
1681rtx_reader::read_rtx_code (const char *code_name)
1682{
1683 RTX_CODE code;
1684 const char *format_ptr;
1685 struct md_name name;
1686 rtx return_rtx;
1687 int c;
1688
1689 /* Linked list structure for making RTXs: */
1690 struct rtx_list
1691 {
1692 struct rtx_list *next;
1693 rtx value; /* Value of this node. */
1694 };
1695
1696#ifndef GENERATOR_FILE
1697 long reuse_id = -1;
1698 /* Handle reuse_rtx ids e.g. "(0|scratch:DI)". */
1699 if (ISDIGIT (code_name[0]))
1700 {
1701 reuse_id = atoi (code_name);
1702 while (char ch = *code_name++)
1703 if (ch == '|')
1704 break;
1705 }
1706
1707 /* Handle "reuse_rtx". */
1708 if (strcmp (code_name, "reuse_rtx") == 0)
1709 {
1710 read_name (&name);
1711 unsigned idx = atoi (name.string);
1712 /* Look it up by ID. */
1713 if (idx >= m_reuse_rtx_by_id.length ())
1714 fatal_with_file_and_line ("invalid reuse index %u", idx);
1715 return_rtx = m_reuse_rtx_by_id[idx];
1716 return return_rtx;
1717 }
1718#endif
1719
1720 /* Handle "const_double_zero". */
1721 if (strcmp (s1: code_name, s2: "const_double_zero") == 0)
1722 {
1723 code = CONST_DOUBLE;
1724 return_rtx = rtx_alloc (code);
1725 memset (s: return_rtx, c: 0, RTX_CODE_SIZE (code));
1726 PUT_CODE (return_rtx, code);
1727 c = read_skip_spaces ();
1728 if (c == ':')
1729 {
1730 file_location loc = read_name (name: &name);
1731 record_potential_iterator_use (group: &modes, loc, x: return_rtx, index: 0,
1732 name: name.string);
1733 }
1734 else
1735 unread_char (ch: c);
1736 return return_rtx;
1737 }
1738
1739 /* If we end up with an insn expression then we free this space below. */
1740 return_rtx = rtx_alloc_for_name (name: code_name);
1741 code = GET_CODE (return_rtx);
1742 format_ptr = GET_RTX_FORMAT (code);
1743 memset (s: return_rtx, c: 0, RTX_CODE_SIZE (code));
1744 PUT_CODE (return_rtx, code);
1745
1746#ifndef GENERATOR_FILE
1747 if (reuse_id != -1)
1748 {
1749 /* Store away for later reuse. */
1750 m_reuse_rtx_by_id.safe_grow_cleared (reuse_id + 1, true);
1751 m_reuse_rtx_by_id[reuse_id] = return_rtx;
1752 }
1753#endif
1754
1755 /* Check for flags. */
1756 read_flags (return_rtx);
1757
1758 /* Read REG_NOTE names for EXPR_LIST and INSN_LIST. */
1759 if ((GET_CODE (return_rtx) == EXPR_LIST
1760 || GET_CODE (return_rtx) == INSN_LIST
1761 || GET_CODE (return_rtx) == INT_LIST)
1762 && !m_in_call_function_usage)
1763 {
1764 char ch = read_char ();
1765 if (ch == ':')
1766 {
1767 read_name (name: &name);
1768 PUT_MODE_RAW (return_rtx,
1769 (machine_mode)parse_reg_note_name (name.string));
1770 }
1771 else
1772 unread_char (ch);
1773 }
1774
1775 /* If what follows is `: mode ', read it and
1776 store the mode in the rtx. */
1777
1778 c = read_skip_spaces ();
1779 if (c == ':')
1780 {
1781 file_location loc = read_name (name: &name);
1782 record_potential_iterator_use (group: &modes, loc, x: return_rtx, index: 0, name: name.string);
1783 }
1784 else
1785 unread_char (ch: c);
1786
1787 if (INSN_CHAIN_CODE_P (code))
1788 {
1789 read_name (name: &name);
1790 INSN_UID (insn: return_rtx) = atoi (nptr: name.string);
1791 }
1792
1793 /* Use the format_ptr to parse the various operands of this rtx. */
1794 for (int idx = 0; format_ptr[idx] != 0; idx++)
1795 return_rtx = read_rtx_operand (return_rtx, idx);
1796
1797 /* Handle any additional information that after the regular fields
1798 (e.g. when parsing function dumps). */
1799 handle_any_trailing_information (return_rtx);
1800
1801 if (CONST_WIDE_INT_P (return_rtx))
1802 {
1803 read_name (name: &name);
1804 validate_const_wide_int (string: name.string);
1805 {
1806 const char *s = name.string;
1807 int len;
1808 int index = 0;
1809 int gs = HOST_BITS_PER_WIDE_INT/4;
1810 int pos;
1811 char * buf = XALLOCAVEC (char, gs + 1);
1812 unsigned HOST_WIDE_INT wi;
1813 int wlen;
1814
1815 /* Skip the leading spaces. */
1816 while (*s && ISSPACE (*s))
1817 s++;
1818
1819 /* Skip the leading 0x. */
1820 gcc_assert (s[0] == '0');
1821 gcc_assert (s[1] == 'x');
1822 s += 2;
1823
1824 len = strlen (s: s);
1825 pos = len - gs;
1826 wlen = (len + gs - 1) / gs; /* Number of words needed */
1827
1828 return_rtx = const_wide_int_alloc (wlen);
1829
1830 while (pos > 0)
1831 {
1832#if HOST_BITS_PER_WIDE_INT == 64
1833 sscanf (s: s + pos, format: "%16" HOST_WIDE_INT_PRINT "x", &wi);
1834#else
1835 sscanf (s + pos, "%8" HOST_WIDE_INT_PRINT "x", &wi);
1836#endif
1837 CWI_ELT (return_rtx, index++) = wi;
1838 pos -= gs;
1839 }
1840 strncpy (dest: buf, src: s, n: gs - pos);
1841 buf [gs - pos] = 0;
1842 sscanf (s: buf, format: "%" HOST_WIDE_INT_PRINT "x", &wi);
1843 CWI_ELT (return_rtx, index++) = wi;
1844 /* TODO: After reading, do we want to canonicalize with:
1845 value = lookup_const_wide_int (value); ? */
1846 }
1847 }
1848
1849 c = read_skip_spaces ();
1850 /* Syntactic sugar for AND and IOR, allowing Lisp-like
1851 arbitrary number of arguments for them. */
1852 if (c == '('
1853 && (GET_CODE (return_rtx) == AND
1854 || GET_CODE (return_rtx) == IOR))
1855 return read_rtx_variadic (form: return_rtx);
1856
1857 unread_char (ch: c);
1858 return return_rtx;
1859}
1860
1861/* Subroutine of read_rtx_code. Parse operand IDX within RETURN_RTX,
1862 based on the corresponding format character within GET_RTX_FORMAT
1863 for the GET_CODE (RETURN_RTX), and return RETURN_RTX.
1864 This is a virtual function, so that function_reader can override
1865 some parsing, and potentially return a different rtx. */
1866
1867rtx
1868rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
1869{
1870 RTX_CODE code = GET_CODE (return_rtx);
1871 const char *format_ptr = GET_RTX_FORMAT (code);
1872 int c;
1873 struct md_name name;
1874
1875 switch (format_ptr[idx])
1876 {
1877 /* 0 means a field for internal use only.
1878 Don't expect it to be present in the input. */
1879 case '0':
1880 if (code == REG)
1881 ORIGINAL_REGNO (return_rtx) = REGNO (return_rtx);
1882 break;
1883
1884 case 'e':
1885 XEXP (return_rtx, idx) = read_nested_rtx ();
1886 break;
1887
1888 case 'u':
1889 XEXP (return_rtx, idx) = read_nested_rtx ();
1890 break;
1891
1892 case 'V':
1893 /* 'V' is an optional vector: if a closeparen follows,
1894 just store NULL for this element. */
1895 c = read_skip_spaces ();
1896 unread_char (ch: c);
1897 if (c == ')')
1898 {
1899 XVEC (return_rtx, idx) = 0;
1900 break;
1901 }
1902 /* Now process the vector. */
1903 /* FALLTHRU */
1904
1905 case 'E':
1906 {
1907 /* Obstack to store scratch vector in. */
1908 struct obstack vector_stack;
1909 int list_counter = 0;
1910 rtvec return_vec = NULL_RTVEC;
1911 rtx saved_rtx = NULL_RTX;
1912
1913 require_char_ws (expected: '[');
1914
1915 /* Add expressions to a list, while keeping a count. */
1916 obstack_init (&vector_stack);
1917 while ((c = read_skip_spaces ()) && c != ']')
1918 {
1919 if (c == EOF)
1920 fatal_expected_char (']', c);
1921 unread_char (ch: c);
1922
1923 rtx value;
1924 int repeat_count = 1;
1925 if (c == 'r')
1926 {
1927 /* Process "repeated xN" directive. */
1928 read_name (name: &name);
1929 if (strcmp (s1: name.string, s2: "repeated"))
1930 fatal_with_file_and_line ("invalid directive \"%s\"\n",
1931 name.string);
1932 read_name (name: &name);
1933 if (!sscanf (s: name.string, format: "x%d", &repeat_count))
1934 fatal_with_file_and_line ("invalid repeat count \"%s\"\n",
1935 name.string);
1936
1937 /* We already saw one of the instances. */
1938 repeat_count--;
1939 value = saved_rtx;
1940 }
1941 else if (c == '(')
1942 value = read_nested_rtx ();
1943 else
1944 fatal_with_file_and_line ("unexpected character in vector");
1945
1946 for (; repeat_count > 0; repeat_count--)
1947 {
1948 list_counter++;
1949 obstack_ptr_grow (&vector_stack, value);
1950 }
1951 saved_rtx = value;
1952 }
1953 if (list_counter > 0)
1954 {
1955 return_vec = rtvec_alloc (list_counter);
1956 memcpy (dest: &return_vec->elem[0], obstack_finish (&vector_stack),
1957 n: list_counter * sizeof (rtx));
1958 }
1959 else if (format_ptr[idx] == 'E')
1960 fatal_with_file_and_line ("vector must have at least one element");
1961 XVEC (return_rtx, idx) = return_vec;
1962 obstack_free (&vector_stack, NULL);
1963 /* close bracket gotten */
1964 }
1965 break;
1966
1967 case 'S':
1968 case 'T':
1969 case 's':
1970 {
1971 char *stringbuf;
1972 int star_if_braced;
1973
1974 c = read_skip_spaces ();
1975 unread_char (ch: c);
1976 if (c == ')')
1977 {
1978 /* 'S' fields are optional and should be NULL if no string
1979 was given. Also allow normal 's' and 'T' strings to be
1980 omitted, treating them in the same way as empty strings. */
1981 XSTR (return_rtx, idx) = (format_ptr[idx] == 'S' ? NULL : "");
1982 break;
1983 }
1984
1985 /* The output template slot of a DEFINE_INSN, DEFINE_INSN_AND_SPLIT,
1986 DEFINE_INSN_AND_REWRITE or DEFINE_PEEPHOLE automatically
1987 gets a star inserted as its first character, if it is
1988 written with a brace block instead of a string constant. */
1989 star_if_braced = (format_ptr[idx] == 'T');
1990
1991 stringbuf = read_string (star_if_braced);
1992 if (!stringbuf)
1993 break;
1994
1995#ifdef GENERATOR_FILE
1996 /* For insn patterns, we want to provide a default name
1997 based on the file and line, like "*foo.md:12", if the
1998 given name is blank. These are only for define_insn and
1999 define_insn_and_split, to aid debugging. */
2000 if (*stringbuf == '\0'
2001 && idx == 0
2002 && (GET_CODE (return_rtx) == DEFINE_INSN
2003 || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT
2004 || GET_CODE (return_rtx) == DEFINE_INSN_AND_REWRITE))
2005 {
2006 const char *old_stringbuf = stringbuf;
2007 struct obstack *string_obstack = get_string_obstack ();
2008 char line_name[20];
2009 const char *read_md_filename = get_filename ();
2010 const char *fn = (read_md_filename ? read_md_filename : "rtx");
2011 const char *slash;
2012 for (slash = fn; *slash; slash ++)
2013 if (*slash == '/' || *slash == '\\' || *slash == ':')
2014 fn = slash + 1;
2015 obstack_1grow (string_obstack, '*');
2016 obstack_grow (string_obstack, fn, strlen (fn));
2017 sprintf (s: line_name, format: ":%d", get_lineno ());
2018 obstack_grow (string_obstack, line_name, strlen (line_name)+1);
2019 stringbuf = XOBFINISH (string_obstack, char *);
2020 copy_md_ptr_loc (new_ptr: stringbuf, old_ptr: old_stringbuf);
2021 }
2022
2023 /* Find attr-names in the string. */
2024 char *str;
2025 char *start, *end, *ptr;
2026 char tmpstr[256];
2027 ptr = &tmpstr[0];
2028 end = stringbuf;
2029 while ((start = strchr (s: end, c: '<')) && (end = strchr (s: start, c: '>')))
2030 {
2031 if ((end - start - 1 > 0)
2032 && (end - start - 1 < (int)sizeof (tmpstr)))
2033 {
2034 strncpy (dest: tmpstr, src: start+1, n: end-start-1);
2035 tmpstr[end-start-1] = 0;
2036 end++;
2037 }
2038 else
2039 break;
2040 struct mapping *m
2041 = (struct mapping *) htab_find (substs.attrs, &ptr);
2042 if (m != 0)
2043 {
2044 /* Here we should find linked subst-iter. */
2045 str = find_subst_iter_by_attr (attr: ptr);
2046 if (str)
2047 m = (struct mapping *) htab_find (substs.iterators, &str);
2048 else
2049 m = 0;
2050 }
2051 if (m != 0)
2052 record_iterator_use (iterator: m, x: return_rtx, index: 0);
2053 }
2054#endif /* #ifdef GENERATOR_FILE */
2055
2056 const char *string_ptr = finalize_string (stringbuf);
2057
2058 if (star_if_braced)
2059 XTMPL (return_rtx, idx) = string_ptr;
2060 else
2061 XSTR (return_rtx, idx) = string_ptr;
2062 }
2063 break;
2064
2065 case 'i':
2066 case 'n':
2067 case 'w':
2068 case 'p':
2069 case 'L':
2070 {
2071 /* Can be an iterator or an integer constant. */
2072 file_location loc = read_name (name: &name);
2073 record_potential_iterator_use (group: &ints, loc, x: return_rtx, index: idx,
2074 name: name.string);
2075 break;
2076 }
2077
2078 case 'r':
2079 read_name (name: &name);
2080 validate_const_int (string: name.string);
2081 set_regno_raw (x: return_rtx, regno: atoi (nptr: name.string), nregs: 1);
2082 REG_ATTRS (return_rtx) = NULL;
2083 break;
2084
2085 default:
2086 gcc_unreachable ();
2087 }
2088
2089 return return_rtx;
2090}
2091
2092/* Read a nested rtx construct from the MD file and return it. */
2093
2094rtx
2095rtx_reader::read_nested_rtx ()
2096{
2097 struct md_name name;
2098 rtx return_rtx;
2099
2100 /* In compact dumps, trailing "(nil)" values can be omitted.
2101 Handle such dumps. */
2102 if (peek_char () == ')')
2103 return NULL_RTX;
2104
2105 require_char_ws (expected: '(');
2106
2107 read_name (name: &name);
2108 if (strcmp (s1: name.string, s2: "nil") == 0)
2109 return_rtx = NULL;
2110 else
2111 return_rtx = read_rtx_code (code_name: name.string);
2112
2113 require_char_ws (expected: ')');
2114
2115 return_rtx = postprocess (x: return_rtx);
2116
2117 return return_rtx;
2118}
2119
2120/* Mutually recursive subroutine of read_rtx which reads
2121 (thing x1 x2 x3 ...) and produces RTL as if
2122 (thing x1 (thing x2 (thing x3 ...))) had been written.
2123 When called, FORM is (thing x1 x2), and the file position
2124 is just past the leading parenthesis of x3. Only works
2125 for THINGs which are dyadic expressions, e.g. AND, IOR. */
2126rtx
2127rtx_reader::read_rtx_variadic (rtx form)
2128{
2129 char c = '(';
2130 rtx p = form, q;
2131
2132 do
2133 {
2134 unread_char (ch: c);
2135
2136 q = rtx_alloc (GET_CODE (p));
2137 PUT_MODE (q, GET_MODE (p));
2138
2139 XEXP (q, 0) = XEXP (p, 1);
2140 XEXP (q, 1) = read_nested_rtx ();
2141
2142 XEXP (p, 1) = q;
2143 p = q;
2144 c = read_skip_spaces ();
2145 }
2146 while (c == '(');
2147 unread_char (ch: c);
2148 return form;
2149}
2150
2151/* Constructor for class rtx_reader. */
2152
2153rtx_reader::rtx_reader (bool compact)
2154: md_reader (compact),
2155 m_in_call_function_usage (false)
2156{
2157 /* Set the global singleton pointer. */
2158 rtx_reader_ptr = this;
2159
2160 one_time_initialization ();
2161}
2162
2163/* Destructor for class rtx_reader. */
2164
2165rtx_reader::~rtx_reader ()
2166{
2167 /* Clear the global singleton pointer. */
2168 rtx_reader_ptr = NULL;
2169}
2170

source code of gcc/read-rtl.cc