123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971 |
- /* Generate code from machine description to emit insns as rtl.
- Copyright (C) 1987 Free Software Foundation, Inc.
- This file is part of GNU CC.
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY. No author or distributor
- accepts responsibility to anyone for the consequences of using it
- or for whether it serves any particular purpose or works at all,
- unless he says so in writing. Refer to the GNU CC General Public
- License for full details.
- Everyone is granted permission to copy, modify and redistribute
- GNU CC, but only under the conditions described in the
- GNU CC General Public License. A copy of this license is
- supposed to have been given to you along with GNU CC so you
- can know your rights and responsibilities. It should be in a
- file named COPYING. Among other things, the copyright notice
- and this notice must be preserved on all copies. */
- /* This program is used to produce insn-recog.c, which contains
- one function called `recog'. This function contains a decision tree
- that recognizes whether an rtx, the argument given to recog,
- is a valid instruction.
- recog returns -1 if the rtx is not valid.
- If the rtx is valid, recog returns a nonnegative number
- which is the insn code number for the pattern that matched.
- This is the same as the order in the machine description of the
- entry that matched. This number can be used as an index into
- insn_templates and insn_n_operands (found in insn-output.c)
- or as an argument to output_insn_hairy (also in insn-output.c). */
- #include <stdio.h>
- #include "rtl.h"
- #include <obstack.h>
- struct obstack obstack;
- struct obstack *current_obstack = &obstack;
- #define obstack_chunk_alloc xmalloc
- #define obstack_chunk_free free
- extern int xmalloc ();
- extern void free ();
- /* Data structure for decision tree for recognizing
- legitimate instructions. */
- struct decision
- {
- int number;
- char *position;
- RTX_CODE code;
- char *exact;
- enum machine_mode mode;
- char *tests;
- int insn_code_number;
- struct decision *next;
- struct decision *success;
- int opno;
- int dupno;
- int dupcount;
- int test_elt_zero_int;
- int elt_zero_int;
- int test_elt_one_int;
- int elt_one_int;
- int ignmode;
- struct decision *afterward;
- int label_needed;
- char *c_test;
- char *reg_class;
- char enforce_mode;
- int veclen;
- };
- /*
- recognize (top)
- {
- staten:
- x = XVECEXP (top, 0, 3);
- if (test_code (GET_CODE (x))
- && test_mode (MODE (x))
- && whatever_else)
- goto statep;
- else if (next one...)
- goto statem:
- goto stater;
- statep:
- actions...;
- return 1;
- statem:
- x = stack[depth--];
- more tests...;
- stateq:
- stack[++depth] = x;
- x = XEXP (stack[depth], 0);
- more tests...;
- stater:
- x = XEXP (stack[depth], 1);
- }
- */
- struct decision *tree;
- int next_number;
- int next_insn_code;
- /* Number of MATCH_DUP's seen so far in this instruction. */
- int dupcount;
- struct decision *add_to_sequence ();
- void add_action ();
- struct decision *try_merge_2 ();
- char *copystr ();
- char *concat ();
- void fatal ();
- struct decision *first;
- /* Construct and return a sequence of decisions
- that will recognize INSN. */
- struct decision *
- make_sequence (pattern)
- rtx pattern;
- {
- register int i;
- rtx x;
- char *c_test = XSTR (pattern, 2);
- struct decision *last;
- dupcount = 0;
- if (XVECLEN (pattern, 1) == 1)
- x = XVECEXP (pattern, 1, 0);
- else
- {
- x = rtx_alloc (PARALLEL);
- XVEC (x, 0) = XVEC (pattern, 1);
- PUT_MODE (x, VOIDmode);
- }
- last = add_to_sequence (x, 0, "");
- if (c_test[0])
- last->c_test = c_test;
- last->insn_code_number = next_insn_code++;
- return first;
- }
- struct decision *
- add_to_sequence (pattern, last, position)
- rtx pattern;
- struct decision *last;
- char *position;
- {
- register RTX_CODE code;
- register struct decision *new
- = (struct decision *) xmalloc (sizeof (struct decision));
- struct decision *this;
- char *newpos;
- register char *fmt;
- register int i;
- int depth;
- int len;
- new->number = next_number++;
- new->position = copystr (position);
- new->exact = 0;
- new->next = 0;
- new->success = 0;
- new->insn_code_number = -1;
- new->tests = 0;
- new->opno = -1;
- new->dupno = -1;
- new->dupcount = -1;
- new->test_elt_zero_int = 0;
- new->test_elt_one_int = 0;
- new->elt_zero_int = 0;
- new->elt_one_int = 0;
- new->enforce_mode = 0;
- new->ignmode = 0;
- new->afterward = 0;
- new->label_needed = 0;
- new->c_test = 0;
- new->reg_class = 0;
- new->veclen = 0;
- this = new;
- if (last == 0)
- first = new;
- else
- last->success = new;
- depth = strlen (position);
- newpos = (char *) alloca (depth + 2);
- strcpy (newpos, position);
- newpos[depth + 1] = 0;
- restart:
- if (pattern == 0)
- {
- new->exact = "0";
- new->code = UNKNOWN;
- new->mode = VOIDmode;
- return new;
- }
- switch (GET_MODE (pattern))
- {
- case 0:
- new->mode = VOIDmode;
- break;
- default:
- new->mode = GET_MODE (pattern);
- break;
- }
- new->code = code = GET_CODE (pattern);;
- switch (code)
- {
- case MATCH_OPERAND:
- new->opno = XINT (pattern, 0);
- new->code = UNKNOWN;
- new->tests = XSTR (pattern, 1);
- if (*new->tests == 0)
- new->tests = 0;
- new->reg_class = XSTR (pattern, 2);
- if (*new->reg_class == 0)
- new->reg_class = 0;
- return new;
- case MATCH_DUP:
- new->dupno = XINT (pattern, 0);
- new->dupcount = dupcount++;
- new->code = UNKNOWN;
- return new;
- case ADDRESS:
- pattern = XEXP (pattern, 0);
- goto restart;
- case PC:
- new->exact = "pc_rtx";
- return new;
- case CC0:
- new->exact = "cc0_rtx";
- return new;
- case CONST_INT:
- if (INTVAL (pattern) == 0)
- {
- new->exact = "const0_rtx";
- return new;
- }
- if (INTVAL (pattern) == 1)
- {
- new->exact = "const1_rtx";
- return new;
- }
- break;
- case SET:
- newpos[depth] = '0';
- new = add_to_sequence (SET_DEST (pattern), new, newpos);
- this->success->enforce_mode = 1;
- newpos[depth] = '1';
- new = add_to_sequence (SET_SRC (pattern), new, newpos);
- return new;
- case STRICT_LOW_PART:
- newpos[depth] = '0';
- new = add_to_sequence (XEXP (pattern, 0), new, newpos);
- this->success->enforce_mode = 1;
- return new;
- case SUBREG:
- this->test_elt_one_int = 1;
- this->elt_one_int = XINT (pattern, 1);
- newpos[depth] = '0';
- new = add_to_sequence (XEXP (pattern, 0), new, newpos);
- this->success->enforce_mode = 1;
- return new;
- case ZERO_EXTRACT:
- case SIGN_EXTRACT:
- newpos[depth] = '0';
- new = add_to_sequence (XEXP (pattern, 0), new, newpos);
- this->success->enforce_mode = 1;
- newpos[depth] = '1';
- new = add_to_sequence (XEXP (pattern, 1), new, newpos);
- newpos[depth] = '2';
- new = add_to_sequence (XEXP (pattern, 2), new, newpos);
- return new;
- }
- fmt = GET_RTX_FORMAT (code);
- len = GET_RTX_LENGTH (code);
- for (i = 0; i < len; i++)
- {
- newpos[depth] = '0' + i;
- if (fmt[i] == 'e' || fmt[i] == 'u')
- new = add_to_sequence (XEXP (pattern, i), new, newpos);
- else if (fmt[i] == 'i' && i == 0)
- {
- this->test_elt_zero_int = 1;
- this->elt_zero_int = XINT (pattern, i);
- }
- else if (fmt[i] == 'i' && i == 1)
- {
- this->test_elt_one_int = 1;
- this->elt_one_int = XINT (pattern, i);
- }
- else if (fmt[i] == 'E')
- {
- register int j;
- /* We do not handle a vector appearing as other than
- the first item, just because nothing uses them
- and by handling only the special case
- we can use one element in newpos for either
- the item number of a subexpression
- or the element number in a vector. */
- if (i != 0)
- abort ();
- this->veclen = XVECLEN (pattern, i);
- for (j = 0; j < XVECLEN (pattern, i); j++)
- {
- newpos[depth] = 'a' + j;
- new = add_to_sequence (XVECEXP (pattern, i, j),
- new, newpos);
- }
- }
- else if (fmt[i] != '0')
- abort ();
- }
- return new;
- }
- /* Merge two decision trees OLD and ADD,
- modifying OLD destructively,
- and return the merged tree. */
- struct decision *
- merge_trees (old, add)
- register struct decision *old, *add;
- {
- while (add)
- {
- register struct decision *next = add->next;
- add->next = 0;
- if (!try_merge_1 (old, add))
- old = try_merge_2 (old, add);
- add = next;
- }
- return old;
- }
- /* Merge ADD into the next-chain starting with OLD
- only if it overlaps a condition already tested in OLD.
- Returns 1 if successful (OLD is modified),
- 0 if nothing has been done. */
- int
- try_merge_1 (old, add)
- register struct decision *old, *add;
- {
- while (old)
- {
- if ((old->position == add->position
- || (old->position && add->position
- && !strcmp (old->position, add->position)))
- && (old->tests == add->tests
- || (old->tests && add->tests && !strcmp (old->tests, add->tests)))
- && (old->c_test == add->c_test
- || (old->c_test && add->c_test && !strcmp (old->c_test, add->c_test)))
- && old->test_elt_zero_int == add->test_elt_zero_int
- && old->elt_zero_int == add->elt_zero_int
- && old->test_elt_one_int == add->test_elt_one_int
- && old->elt_one_int == add->elt_one_int
- && old->veclen == add->veclen
- && old->dupno == add->dupno
- && old->opno == add->opno
- && (old->tests == 0
- || (add->enforce_mode ? no_same_mode (old) : old->next == 0))
- && old->code == add->code
- && old->mode == add->mode)
- {
- old->success = merge_trees (old->success, add->success);
- if (old->insn_code_number >= 0 && add->insn_code_number >= 0)
- fatal ("Two actions at one point in tree.");
- if (old->insn_code_number == -1)
- old->insn_code_number = add->insn_code_number;
- return 1;
- }
- old = old->next;
- }
- return 0;
- }
- /* Merge ADD into the next-chain that starts with OLD,
- preferably after something that tests the same place
- that ADD does.
- The next-chain of ADD itself is ignored, and it is set
- up for entering ADD into the new chain.
- Returns the new chain. */
- struct decision *
- try_merge_2 (old, add)
- struct decision *old, *add;
- {
- register struct decision *p = old, *last = 0, *prev_win = 0;
- /* Put this in after the others that test the same place,
- if there are any. If not, find the last chain element
- and insert there.
- One modification: if this one is NOT a MATCH_OPERAND,
- put it before any MATCH_OPERANDS that test the same place.
- Another: if enforce_mode (i.e. this is first operand of a SET),
- put this after the last thing that tests the same place for
- the same mode. */
- int operand = 0 != add->tests;
- while (p)
- {
- if (p->position == add->position
- || (p->position && add->position
- && !strcmp (p->position, add->position)))
- {
- if (!operand && p->tests)
- break;
- if (prev_win && prev_win->enforce_mode
- && prev_win->mode == add->mode
- && p->mode != add->mode)
- {
- add->next = prev_win->next;
- prev_win->next = add;
- return old;
- }
- prev_win = p;
- }
- else if (prev_win)
- {
- add->next = prev_win->next;
- prev_win->next = add;
- return old;
- }
- last = p;
- p = p->next;
- }
- /* If we leave the loop, p is place to insert before. */
- if (last)
- {
- add->next = last->next;
- last->next = add;
- return old;
- }
- add->next = old;
- return add;
- }
- no_same_mode (node)
- struct decision *node;
- {
- register struct decision *p;
- register enum machine_mode mode = node->mode;
- for (p = node->next; p; p = p->next)
- if (p->mode == mode)
- return 0;
- return 1;
- }
- /* Write out C code to perform the decisions in the tree. */
- write_tree (tree, prevpos, afterward, afterpos)
- struct decision *tree;
- char *prevpos;
- int afterward;
- char *afterpos;
- {
- register struct decision *p, *p1;
- char *pos;
- register int depth;
- int ignmode;
- enum { NO_SWITCH, CODE_SWITCH, MODE_SWITCH } in_switch = NO_SWITCH;
- char modemap[NUM_MACHINE_MODE];
- char codemap[NUM_RTX_CODE];
- pos = prevpos;
- tree->label_needed = 1;
- for (p = tree; p; p = p->next)
- {
- /* Find the next alternative to p
- that might be true when p is true.
- Test that one next if p's successors fail.
- Note that when the `tests' field is nonzero
- it is up to the specified test-function to compare machine modes
- and some (such as general_operand) don't always do so.
- But when inside a switch-on-modes we ignore this and
- consider all modes mutually exclusive. */
- for (p1 = p->next; p1; p1 = p1->next)
- if (((p->code == UNKNOWN || p1->code == UNKNOWN || p->code == p1->code)
- && (p->mode == VOIDmode || p1->mode == VOIDmode
- || p->mode == p1->mode
- || (in_switch != MODE_SWITCH && (p->tests || p1->tests))))
- || strcmp (p1->position, p->position))
- break;
- p->afterward = p1;
- if (p1) p1->label_needed = 1;
- if (in_switch == MODE_SWITCH && (p->mode == VOIDmode || p->tests != 0))
- {
- in_switch = NO_SWITCH;
- printf (" }\n");
- }
- if (in_switch == CODE_SWITCH && p->code == UNKNOWN)
- {
- in_switch = NO_SWITCH;
- printf (" }\n");
- }
- if (p->label_needed)
- printf (" L%d:\n", p->number);
- if (p->success == 0 && p->insn_code_number < 0)
- abort ();
- change_state (pos, p->position);
- pos = p->position;
- depth = strlen (pos);
- ignmode = p->ignmode || pos[depth - 1] == '*' || p->tests;
- if (in_switch == NO_SWITCH)
- {
- /* If p and its alternatives all want the same mode,
- reject all others at once, first, then ignore the mode. */
- if (!ignmode && p->mode != VOIDmode && p->next && same_modes (p, p->mode))
- {
- printf (" if (GET_MODE (x%d) != %smode)\n",
- depth, GET_MODE_NAME (p->mode));
- if (afterward)
- {
- printf (" {\n ");
- change_state (pos, afterpos);
- printf (" goto L%d;\n }\n", afterward);
- }
- else
- printf (" goto ret0;\n");
- clear_modes (p);
- ignmode = 1;
- }
- /* If p and its alternatives all want the same code,
- reject all others at once, first, then ignore the code. */
- if (p->code != UNKNOWN && p->next && same_codes (p, p->code))
- {
- printf (" if (GET_CODE (x%d) != ", depth);
- print_code (p->code);
- printf (")\n");
- if (afterward)
- {
- printf (" {");
- change_state (pos, afterpos);
- printf (" goto L%d; }\n", afterward);
- }
- else
- printf (" goto ret0;\n");
- clear_codes (p);
- }
- }
- /* If p and its alternatives all have different modes
- and there are at least 4 of them, make a switch. */
- if (in_switch == NO_SWITCH && pos[depth-1] != '*')
- {
- register int i;
- bzero (modemap, sizeof modemap);
- for (p1 = p, i = 0; p1 && p1->mode != VOIDmode && p1->tests == 0;
- p1 = p1->next, i++)
- {
- if (! p->enforce_mode && modemap[(int) p1->mode])
- break;
- modemap[(int) p1->mode] = 1;
- }
- if ((p1 == 0 || p1->mode == VOIDmode || p1->tests != 0) && i >= 4)
- {
- in_switch = MODE_SWITCH;
- printf (" switch (GET_MODE (x%d))\n {\n", depth);
- }
- }
- if (in_switch == NO_SWITCH)
- {
- register int i;
- bzero (codemap, sizeof codemap);
- for (p1 = p, i = 0; p1 && p1->code != UNKNOWN; p1 = p1->next, i++)
- {
- if (codemap[(int) p1->code])
- break;
- codemap[(int) p1->code] = 1;
- }
- if ((p1 == 0 || p1->code == UNKNOWN) && i >= 4)
- {
- in_switch = CODE_SWITCH;
- printf (" switch (GET_CODE (x%d))\n {\n", depth);
- }
- }
- if (in_switch == MODE_SWITCH)
- {
- if (modemap[(int) p->mode])
- {
- printf (" case %smode:\n", GET_MODE_NAME (p->mode));
- modemap[(int) p->mode] = 0;
- }
- }
- if (in_switch == CODE_SWITCH)
- {
- if (codemap[(int) p->code])
- {
- printf (" case ");
- print_code (p->code);
- printf (":\n");
- codemap[(int) p->code] = 0;
- }
- }
- printf (" if (");
- if (p->code != UNKNOWN && (p->exact || in_switch != CODE_SWITCH))
- {
- register char *p1;
- if (p->exact)
- printf ("x%d == %s", depth, p->exact);
- else
- {
- printf ("GET_CODE (x%d) == ", depth);
- print_code (p->code);
- }
- printf (" && ");
- }
- if (p->mode && !ignmode && in_switch != MODE_SWITCH)
- printf ("GET_MODE (x%d) == %smode && ",
- depth, GET_MODE_NAME (p->mode));
- if (p->test_elt_zero_int)
- printf ("XINT (x%d, 0) == %d && ", depth, p->elt_zero_int);
- if (p->veclen)
- printf ("XVECLEN (x%d, 0) == %d && ", depth, p->veclen);
- if (p->test_elt_one_int)
- printf ("XINT (x%d, 1) == %d && ", depth, p->elt_one_int);
- if (p->dupno >= 0)
- printf ("rtx_equal_p (x%d, recog_operand[%d]) && ", depth, p->dupno);
- if (p->tests)
- printf ("%s (x%d, %smode)", p->tests, depth,
- GET_MODE_NAME (p->mode));
- else
- printf ("1");
- if (p->opno >= 0)
- printf (")\n { recog_operand[%d] = x%d; ",
- p->opno, depth);
- else
- printf (")\n ");
- if (p->c_test)
- printf ("if (%s) ", p->c_test);
- if (p->insn_code_number >= 0)
- printf ("return %d;", p->insn_code_number);
- else
- printf ("goto L%d;", p->success->number);
- if (p->opno >= 0)
- printf (" }\n");
- else
- printf ("\n");
- /* Now, if inside a switch, branch to next switch member
- that might also need to be tested if this one fails. */
- if (in_switch == CODE_SWITCH)
- {
- /* Find the next alternative to p
- that might be applicable if p was applicable. */
- for (p1 = p->next; p1; p1 = p1->next)
- if (p1->code == UNKNOWN || p->code == p1->code)
- break;
- if (p1 == 0 || p1->code == UNKNOWN)
- printf (" break;\n");
- else if (p1 != p->next)
- {
- printf (" goto L%d;\n", p1->number);
- p1->label_needed = 1;
- }
- }
- if (in_switch == MODE_SWITCH)
- {
- /* Find the next alternative to p
- that might be applicable if p was applicable. */
- for (p1 = p->next; p1; p1 = p1->next)
- if (p1->mode == VOIDmode || p->mode == p1->mode)
- break;
- if (p1 == 0 || p1->mode == VOIDmode)
- printf (" break;\n");
- else if (p1 != p->next)
- {
- printf (" goto L%d;\n", p1->number);
- p1->label_needed = 1;
- }
- }
- }
- if (in_switch != NO_SWITCH)
- printf (" }\n");
- if (afterward)
- {
- change_state (pos, afterpos);
- printf (" goto L%d;\n", afterward);
- }
- else
- printf (" goto ret0;\n");
- for (p = tree; p; p = p->next)
- if (p->success)
- {
- pos = p->position;
- write_tree (p->success, pos,
- p->afterward ? p->afterward->number : afterward,
- p->afterward ? pos : afterpos);
- }
- }
- print_code (code)
- RTX_CODE code;
- {
- register char *p1;
- for (p1 = GET_RTX_NAME (code); *p1; p1++)
- {
- if (*p1 >= 'a' && *p1 <= 'z')
- putchar (*p1 + 'A' - 'a');
- else
- putchar (*p1);
- }
- }
- same_codes (p, code)
- register struct decision *p;
- register RTX_CODE code;
- {
- for (; p; p = p->next)
- if (p->code != code)
- return 0;
- return 1;
- }
- clear_codes (p)
- register struct decision *p;
- {
- for (; p; p = p->next)
- p->code = UNKNOWN;
- }
- same_modes (p, mode)
- register struct decision *p;
- register enum machine_mode mode;
- {
- for (; p; p = p->next)
- if (p->mode != mode || p->tests)
- return 0;
- return 1;
- }
- clear_modes (p)
- register struct decision *p;
- {
- for (; p; p = p->next)
- p->ignmode = 1;
- }
- change_state (oldpos, newpos)
- char *oldpos;
- char *newpos;
- {
- int odepth = strlen (oldpos);
- int depth = odepth;
- int ndepth = strlen (newpos);
- /* Pop up as many levels as necessary. */
- while (strncmp (oldpos, newpos, depth))
- --depth;
- /* Go down to desired level. */
- while (depth < ndepth)
- {
- if (newpos[depth] == '*')
- printf (" x%d = recog_addr_dummy;\n XEXP (x%d, 0) = x%d;\n",
- depth + 1, depth + 1, depth);
- else if (newpos[depth] >= 'a' && newpos[depth] <= 'z')
- printf (" x%d = XVECEXP (x%d, 0, %c);\n",
- depth + 1, depth, '0' + newpos[depth] - 'a');
- else
- printf (" x%d = XEXP (x%d, %c);\n",
- depth + 1, depth, newpos[depth]);
- ++depth;
- }
- }
- char *
- copystr (s1)
- char *s1;
- {
- register char *tem;
- if (s1 == 0)
- return 0;
- tem = (char *) xmalloc (strlen (s1) + 1);
- strcpy (tem, s1);
- return tem;
- }
- char *
- concat (s1, s2)
- char *s1, *s2;
- {
- register char *tem;
- if (s1 == 0)
- return s2;
- if (s2 == 0)
- return s1;
- tem = (char *) xmalloc (strlen (s1) + strlen (s2) + 2);
- strcpy (tem, s1);
- strcat (tem, " ");
- strcat (tem, s2);
- return tem;
- }
- int
- xrealloc (ptr, size)
- char *ptr;
- int size;
- {
- int result = realloc (ptr, size);
- if (!result)
- abort ();
- return result;
- }
- xmalloc (size)
- {
- register int val = malloc (size);
- if (val == 0)
- abort ();
- return val;
- }
- void
- fatal (s, a1, a2)
- {
- fprintf (stderr, "genrecog: ");
- fprintf (stderr, s, a1, a2);
- fprintf (stderr, "\n");
- fprintf (stderr, "after %d instruction definitions\n",
- next_insn_code);
- exit (1);
- }
- main (argc, argv)
- int argc;
- char **argv;
- {
- rtx desc;
- struct decision *tree = 0;
- FILE *infile;
- extern rtx read_rtx ();
- char *startpos;
- register int c;
- obstack_begin (current_obstack, 4060);
- if (argc <= 1)
- fatal ("No input file name.");
- infile = fopen (argv[1], "r");
- if (infile == 0)
- {
- perror (argv[1]);
- exit (1);
- }
- init_rtl ();
- next_insn_code = 0;
- printf ("/* Generated automatically by the program `genrecog'\n\
- from the machine description file `md'. */\n\n");
- /* Read the machine description. */
- while (1)
- {
- c = read_skip_spaces (infile);
- if (c == EOF)
- break;
- ungetc (c, infile);
- desc = read_rtx (infile);
- tree = merge_trees (tree, make_sequence (desc));
- }
- printf ("#include \"config.h\"\n");
- printf ("#include \"rtl.h\"\n");
- printf ("#include \"insn-config.h\"\n");
- printf ("#include \"recog.h\"\n");
- printf ("\n\
- /* `recog' contains a decision tree\n\
- that recognizes whether the rtx X0 is a valid instruction.\n\
- \n\
- recog returns -1 if the rtx is not valid.\n\
- If the rtx is valid, recog returns a nonnegative number\n\
- which is the insn code number for the pattern that matched.\n\
- This is the same as the order in the machine description of the\n\
- entry that matched. This number can be used as an index into\n\
- insn_templates and insn_n_operands (found in insn-output.c)\n\
- or as an argument to output_insn_hairy (also in insn-output.c). */\n\n");
- printf ("rtx recog_operand[MAX_RECOG_OPERANDS];\n\n");
- printf ("rtx *recog_operand_loc[MAX_RECOG_OPERANDS];\n\n");
- printf ("rtx *recog_dup_loc[MAX_DUP_OPERANDS];\n\n");
- printf ("char recog_dup_num[MAX_DUP_OPERANDS];\n\n");
- printf ("extern rtx recog_addr_dummy;\n\n");
- printf ("#define operands recog_operand\n\n");
- printf ("int\nrecog (x0, insn)\n register rtx x0;\n rtx insn;{\n");
- printf (" register rtx x1, x2, x3, x4, x5;\n rtx x6, x7, x8, x9, x10, x11;\n");
- startpos = "";
- write_tree (tree, startpos, 0, "");
- printf (" ret0: return -1;\n}\n");
- return 0;
- }
|