386BSD 0.0 development
[unix-history] / usr / src / usr.bin / gcc / cc1 / genrecog.c
CommitLineData
0ef9e7aa
WJ
1/* Generate code from machine description to emit insns as rtl.
2 Copyright (C) 1987,1988 Free Software Foundation, Inc.
3
4This file is part of GNU CC.
5
6GNU CC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU CC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU CC; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21/* This program is used to produce insn-recog.c, which contains
22 a function called `recog' plus its subroutines.
23 These functions contain a decision tree
24 that recognizes whether an rtx, the argument given to recog,
25 is a valid instruction.
26
27 recog returns -1 if the rtx is not valid.
28 If the rtx is valid, recog returns a nonnegative number
29 which is the insn code number for the pattern that matched.
30 This is the same as the order in the machine description of the
31 entry that matched. This number can be used as an index into
32 insn_templates and insn_n_operands (found in insn-output.c)
33 or as an argument to output_insn_hairy (also in insn-output.c). */
34
35#include <stdio.h>
36#include "config.h"
37#include "rtl.h"
38#include "obstack.h"
39
40struct obstack obstack;
41struct obstack *rtl_obstack = &obstack;
42
43#define obstack_chunk_alloc xmalloc
44#define obstack_chunk_free free
45extern int xmalloc ();
46extern void free ();
47
48/* Data structure for decision tree for recognizing
49 legitimate instructions. */
50
51struct decision
52{
53 int number;
54 char *position;
55 RTX_CODE code;
56 char *exact;
57 enum machine_mode mode;
58 char *tests;
59 int insn_code_number;
60 struct decision *next;
61 struct decision *success;
62 int opno;
63 int dupno;
64 int dupcount;
65 int test_elt_zero_int;
66 int elt_zero_int;
67 int test_elt_one_int;
68 int elt_one_int;
69 int ignmode;
70 struct decision *afterward;
71 int label_needed;
72 char *c_test;
73 char *reg_class;
74 char enforce_mode;
75 int veclen;
76 int subroutine_number;
77};
78
79#define SUBROUTINE_THRESHOLD 50
80
81int next_subroutine_number;
82
83/*
84recognize (top)
85{
86 staten:
87 x = XVECEXP (top, 0, 3);
88 if (test_code (GET_CODE (x))
89 && test_mode (MODE (x))
90 && whatever_else)
91 goto statep;
92 else if (next one...)
93 goto statem:
94 goto stater;
95
96 statep:
97 actions...;
98 return 1;
99
100 statem:
101 x = stack[depth--];
102 more tests...;
103
104 stateq:
105 stack[++depth] = x;
106 x = XEXP (stack[depth], 0);
107 more tests...;
108
109 stater:
110 x = XEXP (stack[depth], 1);
111}
112
113*/
114
115int next_number;
116
117int next_insn_code;
118
119/* Number of MATCH_DUP's seen so far in this instruction. */
120int dupcount;
121
122struct decision *add_to_sequence ();
123struct decision *try_merge_2 ();
124void write_subroutine ();
125void print_code ();
126void clear_codes ();
127void clear_modes ();
128void change_state ();
129void write_tree ();
130char *copystr ();
131char *concat ();
132void fatal ();
133void fancy_abort ();
134void mybzero ();
135\f
136struct decision *first;
137
138/* Construct and return a sequence of decisions
139 that will recognize INSN. */
140
141struct decision *
142make_insn_sequence (insn)
143 rtx insn;
144{
145 rtx x;
146 char *c_test = XSTR (insn, 2);
147 struct decision *last;
148
149 dupcount = 0;
150
151 if (XVECLEN (insn, 1) == 1)
152 x = XVECEXP (insn, 1, 0);
153 else
154 {
155 x = rtx_alloc (PARALLEL);
156 XVEC (x, 0) = XVEC (insn, 1);
157 PUT_MODE (x, VOIDmode);
158 }
159
160 last = add_to_sequence (x, 0, "");
161
162 if (c_test[0])
163 last->c_test = c_test;
164 last->insn_code_number = next_insn_code++;
165
166 return first;
167}
168
169struct decision *
170add_to_sequence (pattern, last, position)
171 rtx pattern;
172 struct decision *last;
173 char *position;
174{
175 register RTX_CODE code;
176 register struct decision *new
177 = (struct decision *) xmalloc (sizeof (struct decision));
178 struct decision *this;
179 char *newpos;
180 register char *fmt;
181 register int i;
182 int depth;
183 int len;
184
185 new->number = next_number++;
186 new->position = copystr (position);
187 new->exact = 0;
188 new->next = 0;
189 new->success = 0;
190 new->insn_code_number = -1;
191 new->tests = 0;
192 new->opno = -1;
193 new->dupno = -1;
194 new->dupcount = -1;
195 new->test_elt_zero_int = 0;
196 new->test_elt_one_int = 0;
197 new->elt_zero_int = 0;
198 new->elt_one_int = 0;
199 new->enforce_mode = 0;
200 new->ignmode = 0;
201 new->afterward = 0;
202 new->label_needed = 0;
203 new->c_test = 0;
204 new->reg_class = 0;
205 new->veclen = 0;
206 new->subroutine_number = 0;
207
208 this = new;
209
210 if (last == 0)
211 first = new;
212 else
213 last->success = new;
214
215 depth = strlen (position);
216 newpos = (char *) alloca (depth + 2);
217 strcpy (newpos, position);
218 newpos[depth + 1] = 0;
219
220 restart:
221
222 if (pattern == 0)
223 {
224 new->exact = "0";
225 new->code = UNKNOWN;
226 new->mode = VOIDmode;
227 return new;
228 }
229
230 switch (GET_MODE (pattern))
231 {
232 case 0:
233 new->mode = VOIDmode;
234 break;
235
236 default:
237 new->mode = GET_MODE (pattern);
238 break;
239 }
240
241 new->code = code = GET_CODE (pattern);
242
243 switch (code)
244 {
245 case MATCH_OPERAND:
246 new->opno = XINT (pattern, 0);
247 new->code = UNKNOWN;
248 new->tests = XSTR (pattern, 1);
249 if (*new->tests == 0)
250 new->tests = 0;
251 new->reg_class = XSTR (pattern, 2);
252 if (*new->reg_class == 0)
253 new->reg_class = 0;
254 return new;
255
256 case MATCH_OPERATOR:
257 new->opno = XINT (pattern, 0);
258 new->code = UNKNOWN;
259 new->tests = XSTR (pattern, 1);
260 if (*new->tests == 0)
261 new->tests = 0;
262 for (i = 0; i < XVECLEN (pattern, 2); i++)
263 {
264 newpos[depth] = i + '0';
265 new = add_to_sequence (XVECEXP (pattern, 2, i), new, newpos);
266 }
267 this->success->enforce_mode = 0;
268 return new;
269
270 case MATCH_DUP:
271 new->dupno = XINT (pattern, 0);
272 new->dupcount = dupcount++;
273 new->code = UNKNOWN;
274 return new;
275
276 case ADDRESS:
277 pattern = XEXP (pattern, 0);
278 goto restart;
279
280 case PC:
281 new->exact = "pc_rtx";
282 return new;
283
284 case CC0:
285 new->exact = "cc0_rtx";
286 return new;
287
288 case CONST_INT:
289 if (INTVAL (pattern) == 0)
290 {
291 new->exact = "const0_rtx";
292 return new;
293 }
294 if (INTVAL (pattern) == 1)
295 {
296 new->exact = "const1_rtx";
297 return new;
298 }
299 break;
300
301 case SET:
302 newpos[depth] = '0';
303 new = add_to_sequence (SET_DEST (pattern), new, newpos);
304 this->success->enforce_mode = 1;
305 newpos[depth] = '1';
306 new = add_to_sequence (SET_SRC (pattern), new, newpos);
307 return new;
308
309 case STRICT_LOW_PART:
310 newpos[depth] = '0';
311 new = add_to_sequence (XEXP (pattern, 0), new, newpos);
312 this->success->enforce_mode = 1;
313 return new;
314
315 case SUBREG:
316 this->test_elt_one_int = 1;
317 this->elt_one_int = XINT (pattern, 1);
318 newpos[depth] = '0';
319 new = add_to_sequence (XEXP (pattern, 0), new, newpos);
320 this->success->enforce_mode = 1;
321 return new;
322
323 case ZERO_EXTRACT:
324 case SIGN_EXTRACT:
325 newpos[depth] = '0';
326 new = add_to_sequence (XEXP (pattern, 0), new, newpos);
327 this->success->enforce_mode = 1;
328 newpos[depth] = '1';
329 new = add_to_sequence (XEXP (pattern, 1), new, newpos);
330 newpos[depth] = '2';
331 new = add_to_sequence (XEXP (pattern, 2), new, newpos);
332 return new;
333 }
334
335 fmt = GET_RTX_FORMAT (code);
336 len = GET_RTX_LENGTH (code);
337 for (i = 0; i < len; i++)
338 {
339 newpos[depth] = '0' + i;
340 if (fmt[i] == 'e' || fmt[i] == 'u')
341 new = add_to_sequence (XEXP (pattern, i), new, newpos);
342 else if (fmt[i] == 'i' && i == 0)
343 {
344 this->test_elt_zero_int = 1;
345 this->elt_zero_int = XINT (pattern, i);
346 }
347 else if (fmt[i] == 'i' && i == 1)
348 {
349 this->test_elt_one_int = 1;
350 this->elt_one_int = XINT (pattern, i);
351 }
352 else if (fmt[i] == 'E')
353 {
354 register int j;
355 /* We do not handle a vector appearing as other than
356 the first item, just because nothing uses them
357 and by handling only the special case
358 we can use one element in newpos for either
359 the item number of a subexpression
360 or the element number in a vector. */
361 if (i != 0)
362 abort ();
363 this->veclen = XVECLEN (pattern, i);
364 for (j = 0; j < XVECLEN (pattern, i); j++)
365 {
366 newpos[depth] = 'a' + j;
367 new = add_to_sequence (XVECEXP (pattern, i, j),
368 new, newpos);
369 }
370 }
371 else if (fmt[i] != '0')
372 abort ();
373 }
374 return new;
375}
376
377/* Merge two decision trees OLD and ADD,
378 modifying OLD destructively,
379 and return the merged tree. */
380
381struct decision *
382merge_trees (old, add)
383 register struct decision *old, *add;
384{
385 while (add)
386 {
387 register struct decision *next = add->next;
388 add->next = 0;
389 if (!try_merge_1 (old, add))
390 old = try_merge_2 (old, add);
391 add = next;
392 }
393 return old;
394}
395
396/* Merge ADD into the next-chain starting with OLD
397 only if it overlaps a condition already tested in OLD.
398 Returns 1 if successful (OLD is modified),
399 0 if nothing has been done. */
400
401int
402try_merge_1 (old, add)
403 register struct decision *old, *add;
404{
405 while (old)
406 {
407 if ((old->position == add->position
408 || (old->position && add->position
409 && !strcmp (old->position, add->position)))
410 && (old->tests == add->tests
411 || (old->tests && add->tests && !strcmp (old->tests, add->tests)))
412 && (old->c_test == add->c_test
413 || (old->c_test && add->c_test && !strcmp (old->c_test, add->c_test)))
414 && old->test_elt_zero_int == add->test_elt_zero_int
415 && old->elt_zero_int == add->elt_zero_int
416 && old->test_elt_one_int == add->test_elt_one_int
417 && old->elt_one_int == add->elt_one_int
418 && old->veclen == add->veclen
419 && old->dupno == add->dupno
420 && old->opno == add->opno
421 && (old->tests == 0
422 || (add->enforce_mode ? no_same_mode (old) : old->next == 0))
423 && old->code == add->code
424 && old->mode == add->mode)
425 {
426 old->success = merge_trees (old->success, add->success);
427 if (old->insn_code_number >= 0 && add->insn_code_number >= 0)
428 fatal ("Two actions at one point in tree.");
429 if (old->insn_code_number == -1)
430 old->insn_code_number = add->insn_code_number;
431 return 1;
432 }
433 old = old->next;
434 }
435 return 0;
436}
437
438/* Merge ADD into the next-chain that starts with OLD,
439 preferably after something that tests the same place
440 that ADD does.
441 The next-chain of ADD itself is ignored, and it is set
442 up for entering ADD into the new chain.
443 Returns the new chain. */
444
445struct decision *
446try_merge_2 (old, add)
447 struct decision *old, *add;
448{
449 register struct decision *p;
450 struct decision *last = 0;
451 struct decision *last_same_place = 0;
452
453 /* Put this in after the others that test the same place,
454 if there are any. If not, find the last chain element
455 and insert there.
456
457 One modification: if this one is NOT a MATCH_OPERAND,
458 put it before any MATCH_OPERANDS that test the same place.
459
460 Another: if enforce_mode (i.e. this is first operand of a SET),
461 put this after the last thing that tests the same place for
462 the same mode. */
463
464 int operand = 0 != add->tests;
465
466 for (p = old; p; p = p->next)
467 {
468 if (p->position == add->position
469 || (p->position && add->position
470 && !strcmp (p->position, add->position)))
471 {
472 last_same_place = p;
473 /* If enforce_mode, segregate the modes in numerical order. */
474 if (p->enforce_mode && (int) add->mode < (int) p->mode)
475 break;
476#if 0
477 /* Keep explicit decompositions before those that test predicates.
478 If enforce_mode, do this separately within each mode. */
479 if (! p->enforce_mode || p->mode == add->mode)
480 if (!operand && p->tests)
481 break;
482#endif
483 }
484 /* If this is past the end of the decisions at the same place as ADD,
485 stop looking now; add ADD before here. */
486 else if (last_same_place)
487 break;
488 last = p;
489 }
490
491 /* Insert before P, which means after LAST. */
492
493 if (last)
494 {
495 add->next = last->next;
496 last->next = add;
497 return old;
498 }
499
500 add->next = old;
501 return add;
502}
503
504int
505no_same_mode (node)
506 struct decision *node;
507{
508 register struct decision *p;
509 register enum machine_mode mode = node->mode;
510
511 for (p = node->next; p; p = p->next)
512 if (p->mode == mode)
513 return 0;
514
515 return 1;
516}
517\f
518/* Count the number of subnodes of node NODE, assumed to be the start
519 of a next-chain. If the number is high enough, make NODE start
520 a separate subroutine in the C code that is generated. */
521
522int
523break_out_subroutines (node)
524 struct decision *node;
525{
526 int size = 0;
527 struct decision *sub;
528 for (sub = node; sub; sub = sub->next)
529 size += 1 + break_out_subroutines (sub->success);
530 if (size > SUBROUTINE_THRESHOLD)
531 {
532 node->subroutine_number = ++next_subroutine_number;
533 write_subroutine (node);
534 size = 1;
535 }
536 return size;
537}
538
539void
540write_subroutine (tree)
541 struct decision *tree;
542{
543 printf ("int\nrecog_%d (x0, insn)\n register rtx x0;\n rtx insn;\n{\n",
544 tree->subroutine_number);
545 printf (" register rtx x1, x2, x3, x4, x5;\n rtx x6, x7, x8, x9, x10, x11;\n");
546 printf (" int tem;\n");
547 write_tree (tree, "", 0, "", 1);
548 printf (" ret0: return -1;\n}\n\n");
549}
550\f
551/* Write out C code to perform the decisions in the tree. */
552
553void
554write_tree (tree, prevpos, afterward, afterpos, initial)
555 struct decision *tree;
556 char *prevpos;
557 int afterward;
558 char *afterpos;
559 int initial;
560{
561 register struct decision *p, *p1;
562 char *pos;
563 register int depth;
564 int ignmode;
565 enum anon1 { NO_SWITCH, CODE_SWITCH, MODE_SWITCH } in_switch = NO_SWITCH;
566 char modemap[NUM_MACHINE_MODES];
567 char codemap[NUM_RTX_CODE];
568
569 pos = prevpos;
570
571 if (tree->subroutine_number > 0 && ! initial)
572 {
573 printf (" L%d:\n", tree->number);
574
575 if (afterward)
576 {
577 printf (" tem = recog_%d (x0, insn);\n",
578 tree->subroutine_number);
579 printf (" if (tem >= 0) return tem;\n");
580 change_state (pos, afterpos);
581 printf (" goto L%d;\n", afterward);
582 }
583 else
584 printf (" return recog_%d (x0, insn);\n",
585 tree->subroutine_number);
586 return;
587 }
588
589 tree->label_needed = 1;
590 for (p = tree; p; p = p->next)
591 {
592 /* Find the next alternative to p
593 that might be true when p is true.
594 Test that one next if p's successors fail.
595 Note that when the `tests' field is nonzero
596 it is up to the specified test-function to compare machine modes
597 and some (such as general_operand) don't always do so.
598 But when inside a switch-on-modes we ignore this and
599 consider all modes mutually exclusive. */
600 for (p1 = p->next; p1; p1 = p1->next)
601 if (((p->code == UNKNOWN || p1->code == UNKNOWN || p->code == p1->code)
602 && (p->mode == VOIDmode || p1->mode == VOIDmode
603 || p->mode == p1->mode
604 || (in_switch != MODE_SWITCH && (p->tests || p1->tests))))
605 || strcmp (p1->position, p->position))
606 break;
607 p->afterward = p1;
608 if (p1) p1->label_needed = 1;
609
610 if (in_switch == MODE_SWITCH
611 && (p->mode == VOIDmode || (! p->enforce_mode && p->tests != 0)))
612 {
613 in_switch = NO_SWITCH;
614 printf (" }\n");
615 }
616 if (in_switch == CODE_SWITCH && p->code == UNKNOWN)
617 {
618 in_switch = NO_SWITCH;
619 printf (" }\n");
620 }
621
622 if (p->label_needed)
623 printf (" L%d:\n", p->number);
624
625 if (p->success == 0 && p->insn_code_number < 0)
626 abort ();
627
628 change_state (pos, p->position);
629 pos = p->position;
630 depth = strlen (pos);
631
632 ignmode = p->ignmode || pos[depth - 1] == '*' || p->tests;
633
634 if (in_switch == NO_SWITCH)
635 {
636 /* If p and its alternatives all want the same mode,
637 reject all others at once, first, then ignore the mode. */
638 if (!ignmode && p->mode != VOIDmode && p->next && same_modes (p, p->mode))
639 {
640 printf (" if (GET_MODE (x%d) != %smode)\n",
641 depth, GET_MODE_NAME (p->mode));
642 if (afterward)
643 {
644 printf (" {\n ");
645 change_state (pos, afterpos);
646 printf (" goto L%d;\n }\n", afterward);
647 }
648 else
649 printf (" goto ret0;\n");
650 clear_modes (p);
651 ignmode = 1;
652 }
653
654 /* If p and its alternatives all want the same code,
655 reject all others at once, first, then ignore the code. */
656 if (p->code != UNKNOWN && p->next && same_codes (p, p->code))
657 {
658 printf (" if (GET_CODE (x%d) != ", depth);
659 print_code (p->code);
660 printf (")\n");
661 if (afterward)
662 {
663 printf (" {");
664 change_state (pos, afterpos);
665 printf (" goto L%d; }\n", afterward);
666 }
667 else
668 printf (" goto ret0;\n");
669 clear_codes (p);
670 }
671 }
672
673 /* If p and its alternatives all have different modes
674 and there are at least 4 of them, make a switch. */
675 if (in_switch == NO_SWITCH && pos[depth-1] != '*')
676 {
677 register int i;
678 int lose = 0;
679
680 mybzero (modemap, sizeof modemap);
681 for (p1 = p, i = 0;
682 (p1 && p1->mode != VOIDmode
683 && (p1->tests == 0 || p1->enforce_mode));
684 p1 = p1->next, i++)
685 {
686 if (! p->enforce_mode && modemap[(int) p1->mode])
687 {
688 lose = 1;
689 break;
690 }
691 modemap[(int) p1->mode] = 1;
692 }
693 if (!lose && i >= 4)
694 {
695 in_switch = MODE_SWITCH;
696 printf (" switch (GET_MODE (x%d))\n {\n", depth);
697 }
698 }
699
700 if (in_switch == NO_SWITCH)
701 {
702 register int i;
703 mybzero (codemap, sizeof codemap);
704 for (p1 = p, i = 0; p1 && p1->code != UNKNOWN; p1 = p1->next, i++)
705 {
706 if (codemap[(int) p1->code])
707 break;
708 codemap[(int) p1->code] = 1;
709 }
710 if ((p1 == 0 || p1->code == UNKNOWN) && i >= 4)
711 {
712 in_switch = CODE_SWITCH;
713 printf (" switch (GET_CODE (x%d))\n {\n", depth);
714 }
715 }
716
717 if (in_switch == MODE_SWITCH)
718 {
719 if (modemap[(int) p->mode])
720 {
721 printf (" case %smode:\n", GET_MODE_NAME (p->mode));
722 modemap[(int) p->mode] = 0;
723 }
724 }
725 if (in_switch == CODE_SWITCH)
726 {
727 if (codemap[(int) p->code])
728 {
729 printf (" case ");
730 print_code (p->code);
731 printf (":\n");
732 codemap[(int) p->code] = 0;
733 }
734 }
735
736 printf (" if (");
737 if (p->exact || (p->code != UNKNOWN && in_switch != CODE_SWITCH))
738 {
739 if (p->exact)
740 printf ("x%d == %s", depth, p->exact);
741 else
742 {
743 printf ("GET_CODE (x%d) == ", depth);
744 print_code (p->code);
745 }
746 printf (" && ");
747 }
748 if (p->mode != VOIDmode && !ignmode && in_switch != MODE_SWITCH)
749 printf ("GET_MODE (x%d) == %smode && ",
750 depth, GET_MODE_NAME (p->mode));
751 if (p->test_elt_zero_int)
752 printf ("XINT (x%d, 0) == %d && ", depth, p->elt_zero_int);
753 if (p->veclen)
754 printf ("XVECLEN (x%d, 0) == %d && ", depth, p->veclen);
755 if (p->test_elt_one_int)
756 printf ("XINT (x%d, 1) == %d && ", depth, p->elt_one_int);
757 if (p->dupno >= 0)
758 printf ("rtx_equal_p (x%d, recog_operand[%d]) && ", depth, p->dupno);
759 if (p->tests)
760 printf ("%s (x%d, %smode)", p->tests, depth,
761 GET_MODE_NAME (p->mode));
762 else
763 printf ("1");
764
765 if (p->opno >= 0)
766 printf (")\n { recog_operand[%d] = x%d; ",
767 p->opno, depth);
768 else
769 printf (")\n ");
770
771 if (p->c_test)
772 printf ("if (%s) ", p->c_test);
773
774 if (p->insn_code_number >= 0)
775 printf ("return %d;", p->insn_code_number);
776 else
777 printf ("goto L%d;", p->success->number);
778
779 if (p->opno >= 0)
780 printf (" }\n");
781 else
782 printf ("\n");
783
784 /* Now, if inside a switch, branch to next switch member
785 that might also need to be tested if this one fails. */
786
787 if (in_switch == CODE_SWITCH)
788 {
789 /* Find the next alternative to p
790 that might be applicable if p was applicable. */
791 for (p1 = p->next; p1; p1 = p1->next)
792 if (p1->code == UNKNOWN || p->code == p1->code)
793 break;
794 if (p1 == 0 || p1->code == UNKNOWN)
795 printf (" break;\n");
796 else if (p1 != p->next)
797 {
798 printf (" goto L%d;\n", p1->number);
799 p1->label_needed = 1;
800 }
801 }
802
803 if (in_switch == MODE_SWITCH)
804 {
805 /* Find the next alternative to p
806 that might be applicable if p was applicable. */
807 for (p1 = p->next; p1; p1 = p1->next)
808 if (p1->mode == VOIDmode || p->mode == p1->mode)
809 break;
810 if (p1 == 0 || p1->mode == VOIDmode)
811 printf (" break;\n");
812 else if (p1 != p->next)
813 {
814 printf (" goto L%d;\n", p1->number);
815 p1->label_needed = 1;
816 }
817 }
818 }
819
820 if (in_switch != NO_SWITCH)
821 printf (" }\n");
822
823 if (afterward)
824 {
825 change_state (pos, afterpos);
826 printf (" goto L%d;\n", afterward);
827 }
828 else
829 printf (" goto ret0;\n");
830
831 for (p = tree; p; p = p->next)
832 if (p->success)
833 {
834 {
835 pos = p->position;
836 write_tree (p->success, pos,
837 p->afterward ? p->afterward->number : afterward,
838 p->afterward ? pos : afterpos,
839 0);
840 }
841 }
842}
843
844void
845print_code (code)
846 RTX_CODE code;
847{
848 register char *p1;
849 for (p1 = GET_RTX_NAME (code); *p1; p1++)
850 {
851 if (*p1 >= 'a' && *p1 <= 'z')
852 putchar (*p1 + 'A' - 'a');
853 else
854 putchar (*p1);
855 }
856}
857
858int
859same_codes (p, code)
860 register struct decision *p;
861 register RTX_CODE code;
862{
863 for (; p; p = p->next)
864 if (p->code != code)
865 return 0;
866
867 return 1;
868}
869
870void
871clear_codes (p)
872 register struct decision *p;
873{
874 for (; p; p = p->next)
875 p->code = UNKNOWN;
876}
877
878int
879same_modes (p, mode)
880 register struct decision *p;
881 register enum machine_mode mode;
882{
883 for (; p; p = p->next)
884 if (p->mode != mode || p->tests)
885 return 0;
886
887 return 1;
888}
889
890void
891clear_modes (p)
892 register struct decision *p;
893{
894 for (; p; p = p->next)
895 p->ignmode = 1;
896}
897\f
898void
899change_state (oldpos, newpos)
900 char *oldpos;
901 char *newpos;
902{
903 int odepth = strlen (oldpos);
904 int depth = odepth;
905 int ndepth = strlen (newpos);
906
907 /* Pop up as many levels as necessary. */
908
909 while (strncmp (oldpos, newpos, depth))
910 --depth;
911
912 /* Go down to desired level. */
913
914 while (depth < ndepth)
915 {
916 if (newpos[depth] == '*')
917 printf (" x%d = recog_addr_dummy;\n XEXP (x%d, 0) = x%d;\n",
918 depth + 1, depth + 1, depth);
919 else if (newpos[depth] >= 'a' && newpos[depth] <= 'z')
920 printf (" x%d = XVECEXP (x%d, 0, %d);\n",
921 depth + 1, depth, newpos[depth] - 'a');
922 else
923 printf (" x%d = XEXP (x%d, %c);\n",
924 depth + 1, depth, newpos[depth]);
925 ++depth;
926 }
927}
928\f
929char *
930copystr (s1)
931 char *s1;
932{
933 register char *tem;
934
935 if (s1 == 0)
936 return 0;
937
938 tem = (char *) xmalloc (strlen (s1) + 1);
939 strcpy (tem, s1);
940
941 return tem;
942}
943
944void
945mybzero (b, length)
946 register char *b;
947 register int length;
948{
949 while (length-- > 0)
950 *b++ = 0;
951}
952
953char *
954concat (s1, s2)
955 char *s1, *s2;
956{
957 register char *tem;
958
959 if (s1 == 0)
960 return s2;
961 if (s2 == 0)
962 return s1;
963
964 tem = (char *) xmalloc (strlen (s1) + strlen (s2) + 2);
965 strcpy (tem, s1);
966 strcat (tem, " ");
967 strcat (tem, s2);
968
969 return tem;
970}
971
972int
973xrealloc (ptr, size)
974 char *ptr;
975 int size;
976{
977 int result = realloc (ptr, size);
978 if (!result)
979 fatal ("virtual memory exhausted");
980 return result;
981}
982
983int
984xmalloc (size)
985{
986 register int val = malloc (size);
987
988 if (val == 0)
989 fatal ("virtual memory exhausted");
990 return val;
991}
992
993void
994fatal (s, a1, a2)
995 char *s;
996{
997 fprintf (stderr, "genrecog: ");
998 fprintf (stderr, s, a1, a2);
999 fprintf (stderr, "\n");
1000 fprintf (stderr, "after %d instruction definitions\n",
1001 next_insn_code);
1002 exit (FATAL_EXIT_CODE);
1003}
1004
1005/* More 'friendly' abort that prints the line and file.
1006 config.h can #define abort fancy_abort if you like that sort of thing. */
1007
1008void
1009fancy_abort ()
1010{
1011 fatal ("Internal gcc abort.");
1012}
1013\f
1014int
1015main (argc, argv)
1016 int argc;
1017 char **argv;
1018{
1019 rtx desc;
1020 struct decision *tree = 0;
1021 FILE *infile;
1022 extern rtx read_rtx ();
1023 register int c;
1024
1025 obstack_init (rtl_obstack);
1026
1027 if (argc <= 1)
1028 fatal ("No input file name.");
1029
1030 infile = fopen (argv[1], "r");
1031 if (infile == 0)
1032 {
1033 perror (argv[1]);
1034 exit (FATAL_EXIT_CODE);
1035 }
1036
1037 init_rtl ();
1038 next_insn_code = 0;
1039
1040 printf ("/* Generated automatically by the program `genrecog'\n\
1041from the machine description file `md'. */\n\n");
1042
1043 /* Read the machine description. */
1044
1045 while (1)
1046 {
1047 c = read_skip_spaces (infile);
1048 if (c == EOF)
1049 break;
1050 ungetc (c, infile);
1051
1052 desc = read_rtx (infile);
1053 if (GET_CODE (desc) == DEFINE_INSN)
1054 tree = merge_trees (tree, make_insn_sequence (desc));
1055 if (GET_CODE (desc) == DEFINE_PEEPHOLE
1056 || GET_CODE (desc) == DEFINE_EXPAND)
1057 next_insn_code++;
1058 }
1059
1060 printf ("#include \"config.h\"\n");
1061 printf ("#include \"rtl.h\"\n");
1062 printf ("#include \"insn-config.h\"\n");
1063 printf ("#include \"recog.h\"\n");
1064 printf ("#include \"real.h\"\n");
1065 printf ("\n\
1066/* `recog' contains a decision tree\n\
1067 that recognizes whether the rtx X0 is a valid instruction.\n\
1068\n\
1069 recog returns -1 if the rtx is not valid.\n\
1070 If the rtx is valid, recog returns a nonnegative number\n\
1071 which is the insn code number for the pattern that matched.\n");
1072 printf (" This is the same as the order in the machine description of\n\
1073 the entry that matched. This number can be used as an index into\n\
1074 insn_templates and insn_n_operands (found in insn-output.c)\n\
1075 or as an argument to output_insn_hairy (also in insn-output.c). */\n\n");
1076
1077 printf ("rtx recog_operand[MAX_RECOG_OPERANDS];\n\n");
1078 printf ("rtx *recog_operand_loc[MAX_RECOG_OPERANDS];\n\n");
1079 printf ("rtx *recog_dup_loc[MAX_DUP_OPERANDS];\n\n");
1080 printf ("char recog_dup_num[MAX_DUP_OPERANDS];\n\n");
1081 printf ("extern rtx recog_addr_dummy;\n\n");
1082 printf ("#define operands recog_operand\n\n");
1083
1084 break_out_subroutines (tree);
1085
1086 printf ("int\nrecog (x0, insn)\n register rtx x0;\n rtx insn;\n{\n");
1087 printf (" register rtx x1, x2, x3, x4, x5;\n rtx x6, x7, x8, x9, x10, x11;\n");
1088 printf (" int tem;\n");
1089
1090 write_tree (tree, "", 0, "", 1);
1091 printf (" ret0: return -1;\n}\n");
1092
1093 fflush (stdout);
1094 exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
1095}