1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069 |
- /* Generate code from machine description to emit insns as rtl.
- Copyright (C) 1987,1988 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
- a function called `recog' plus its subroutines.
- These functions contain 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 "config.h"
- #include "rtl.h"
- #include "obstack.h"
- struct obstack obstack;
- struct obstack *rtl_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;
- int subroutine_number;
- };
- #define SUBROUTINE_THRESHOLD 50
- int next_subroutine_number;
- /*
- 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);
- }
- */
- 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 ();
- struct decision *try_merge_2 ();
- void write_subroutine ();
- void print_code ();
- void clear_codes ();
- void clear_modes ();
- void change_state ();
- void write_tree ();
- char *copystr ();
- char *concat ();
- void fatal ();
- void mybzero ();
- struct decision *first;
- /* Construct and return a sequence of decisions
- that will recognize INSN. */
- struct decision *
- make_insn_sequence (insn)
- rtx insn;
- {
- rtx x;
- char *c_test = XSTR (insn, 2);
- struct decision *last;
- dupcount = 0;
- if (XVECLEN (insn, 1) == 1)
- x = XVECEXP (insn, 1, 0);
- else
- {
- x = rtx_alloc (PARALLEL);
- XVEC (x, 0) = XVEC (insn, 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;
- new->subroutine_number = 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;
- struct decision *last = 0;
- struct decision *last_same_place = 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;
- for (p = old; p; p = p->next)
- {
- if (p->position == add->position
- || (p->position && add->position
- && !strcmp (p->position, add->position)))
- {
- last_same_place = p;
- /* If enforce_mode, segregate the modes in numerical order. */
- if (p->enforce_mode && (int) add->mode < (int) p->mode)
- break;
- /* Keep explicit decompositions before those that test predicates.
- If enforce_mode, do this separately within each mode. */
- if (! p->enforce_mode || p->mode == add->mode)
- if (!operand && p->tests)
- break;
- }
- /* If this is past the end of the decisions at the same place as ADD,
- stop looking now; add ADD before here. */
- else if (last_same_place)
- break;
- last = p;
- }
- /* Insert before P, which means after LAST. */
- if (last)
- {
- add->next = last->next;
- last->next = add;
- return old;
- }
- add->next = old;
- return add;
- }
- int
- 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;
- }
- /* Count the number of subnodes of node NODE, assumed to be the start
- of a next-chain. If the number is high enough, make NODE start
- a separate subroutine in the C code that is generated. */
- int
- break_out_subroutines (node)
- struct decision *node;
- {
- int size = 0;
- struct decision *sub;
- for (sub = node; sub; sub = sub->next)
- size += 1 + break_out_subroutines (sub->success);
- if (size > SUBROUTINE_THRESHOLD)
- {
- node->subroutine_number = ++next_subroutine_number;
- write_subroutine (node);
- size = 1;
- }
- return size;
- }
- void
- write_subroutine (tree)
- struct decision *tree;
- {
- printf ("int\nrecog_%d (x0, insn)\n register rtx x0;\n rtx insn;\n{\n",
- tree->subroutine_number);
- printf (" register rtx x1, x2, x3, x4, x5;\n rtx x6, x7, x8, x9, x10, x11;\n");
- printf (" int tem;\n");
- write_tree (tree, "", 0, "", 1);
- printf (" ret0: return -1;\n}\n\n");
- }
- /* Write out C code to perform the decisions in the tree. */
- void
- write_tree (tree, prevpos, afterward, afterpos, initial)
- struct decision *tree;
- char *prevpos;
- int afterward;
- char *afterpos;
- int initial;
- {
- 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_MODES];
- char codemap[NUM_RTX_CODE];
- pos = prevpos;
- if (tree->subroutine_number > 0 && ! initial)
- {
- printf (" L%d:\n", tree->number);
- if (afterward)
- {
- printf (" tem = recog_%d (x0, insn);\n",
- tree->subroutine_number);
- printf (" if (tem >= 0) return tem;\n");
- change_state (pos, afterpos);
- printf (" goto L%d;\n", afterward);
- }
- else
- printf (" return recog_%d (x0, insn);\n",
- tree->subroutine_number);
- return;
- }
- 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->enforce_mode && 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;
- int lose = 0;
- mybzero (modemap, sizeof modemap);
- for (p1 = p, i = 0;
- (p1 && p1->mode != VOIDmode
- && (p1->tests == 0 || p1->enforce_mode));
- p1 = p1->next, i++)
- {
- if (! p->enforce_mode && modemap[(int) p1->mode])
- {
- lose = 1;
- break;
- }
- modemap[(int) p1->mode] = 1;
- }
- if (!lose && i >= 4)
- {
- in_switch = MODE_SWITCH;
- printf (" switch (GET_MODE (x%d))\n {\n", depth);
- }
- }
- if (in_switch == NO_SWITCH)
- {
- register int i;
- mybzero (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->exact || (p->code != UNKNOWN && in_switch != CODE_SWITCH))
- {
- 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,
- 0);
- }
- }
- }
- void
- 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);
- }
- }
- int
- 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;
- }
- void
- clear_codes (p)
- register struct decision *p;
- {
- for (; p; p = p->next)
- p->code = UNKNOWN;
- }
- int
- 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;
- }
- void
- clear_modes (p)
- register struct decision *p;
- {
- for (; p; p = p->next)
- p->ignmode = 1;
- }
- void
- 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;
- }
- void
- mybzero (b, length)
- register char *b;
- register int length;
- {
- while (length-- > 0)
- *b++ = 0;
- }
- 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)
- fatal ("virtual memory exhausted");
- return result;
- }
- int
- xmalloc (size)
- {
- register int val = malloc (size);
- if (val == 0)
- fatal ("virtual memory exhausted");
- 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 (FATAL_EXIT_CODE);
- }
- int
- main (argc, argv)
- int argc;
- char **argv;
- {
- rtx desc;
- struct decision *tree = 0;
- FILE *infile;
- extern rtx read_rtx ();
- register int c;
- obstack_init (rtl_obstack);
- if (argc <= 1)
- fatal ("No input file name.");
- infile = fopen (argv[1], "r");
- if (infile == 0)
- {
- perror (argv[1]);
- exit (FATAL_EXIT_CODE);
- }
- 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);
- if (GET_CODE (desc) == DEFINE_INSN)
- tree = merge_trees (tree, make_insn_sequence (desc));
- if (GET_CODE (desc) == DEFINE_PEEPHOLE
- || GET_CODE (desc) == DEFINE_EXPAND)
- next_insn_code++;
- }
- 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");
- printf (" This is the same as the order in the machine description of\n\
- the 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");
- break_out_subroutines (tree);
- printf ("int\nrecog (x0, insn)\n register rtx x0;\n rtx insn;\n{\n");
- printf (" register rtx x1, x2, x3, x4, x5;\n rtx x6, x7, x8, x9, x10, x11;\n");
- printf (" int tem;\n");
- write_tree (tree, "", 0, "", 1);
- printf (" ret0: return -1;\n}\n");
- fflush (stdout);
- exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
- }
|