diff options
Diffstat (limited to 'contrib/gcc/genrecog.c')
-rw-r--r-- | contrib/gcc/genrecog.c | 1834 |
1 files changed, 0 insertions, 1834 deletions
diff --git a/contrib/gcc/genrecog.c b/contrib/gcc/genrecog.c deleted file mode 100644 index 546f922cccb5..000000000000 --- a/contrib/gcc/genrecog.c +++ /dev/null @@ -1,1834 +0,0 @@ -/* Generate code from machine description to recognize rtl as insns. - Copyright (C) 1987, 88, 92-95, 97-98, 1999 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - - -/* 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 various - insn_* tables, such as insn_template, insn_outfun, and insn_n_operands - (found in insn-output.c). - - The third argument to recog is an optional pointer to an int. - If present, recog will accept a pattern if it matches except for - missing CLOBBER expressions at the end. In that case, the value - pointed to by the optional pointer will be set to the number of - CLOBBERs that need to be added (it should be initialized to zero by - the caller). If it is set nonzero, the caller should allocate a - PARALLEL of the appropriate size, copy the initial entries, and call - add_clobbers (found in insn-emit.c) to fill in the CLOBBERs. - - This program also generates the function `split_insns', - which returns 0 if the rtl could not be split, or - it returns the split rtl in a SEQUENCE. */ - -#include "hconfig.h" -#include "system.h" -#include "rtl.h" -#include "obstack.h" - -#define OUTPUT_LABEL(INDENT_STRING, LABEL_NUMBER) \ - printf("%sL%d: ATTRIBUTE_UNUSED_LABEL\n", (INDENT_STRING), (LABEL_NUMBER)) - -static struct obstack obstack; -struct obstack *rtl_obstack = &obstack; - -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free - -/* Holds an array of names indexed by insn_code_number. */ -char **insn_name_ptr = 0; -int insn_name_ptr_size = 0; - -/* Data structure for a listhead of decision trees. The alternatives - to a node are kept in a doublely-linked list so we can easily add nodes - to the proper place when merging. */ - -struct decision_head { struct decision *first, *last; }; - -/* Data structure for decision tree for recognizing - legitimate instructions. */ - -struct decision -{ - int number; /* Node number, used for labels */ - char *position; /* String denoting position in pattern */ - RTX_CODE code; /* Code to test for or UNKNOWN to suppress */ - char ignore_code; /* If non-zero, need not test code */ - char ignore_mode; /* If non-zero, need not test mode */ - int veclen; /* Length of vector, if nonzero */ - enum machine_mode mode; /* Machine mode of node */ - char enforce_mode; /* If non-zero, test `mode' */ - char retest_code, retest_mode; /* See write_tree_1 */ - int test_elt_zero_int; /* Nonzero if should test XINT (rtl, 0) */ - int elt_zero_int; /* Required value for XINT (rtl, 0) */ - int test_elt_one_int; /* Nonzero if should test XINT (rtl, 1) */ - int elt_one_int; /* Required value for XINT (rtl, 1) */ - int test_elt_zero_wide; /* Nonzero if should test XWINT (rtl, 0) */ - HOST_WIDE_INT elt_zero_wide; /* Required value for XWINT (rtl, 0) */ - const char *tests; /* If nonzero predicate to call */ - int pred; /* `preds' index of predicate or -1 */ - char *c_test; /* Additional test to perform */ - struct decision_head success; /* Nodes to test on success */ - int insn_code_number; /* Insn number matched, if success */ - int num_clobbers_to_add; /* Number of CLOBBERs to be added to pattern */ - struct decision *next; /* Node to test on failure */ - struct decision *prev; /* Node whose failure tests us */ - struct decision *afterward; /* Node to test on success, but failure of - successor nodes */ - int opno; /* Operand number, if >= 0 */ - int dupno; /* Number of operand to compare against */ - int label_needed; /* Nonzero if label needed when writing tree */ - int subroutine_number; /* Number of subroutine this node starts */ -}; - -#define SUBROUTINE_THRESHOLD 50 - -static int next_subroutine_number; - -/* We can write two types of subroutines: One for insn recognition and - one to split insns. This defines which type is being written. */ - -enum routine_type {RECOG, SPLIT}; - -/* Next available node number for tree nodes. */ - -static int next_number; - -/* Next number to use as an insn_code. */ - -static int next_insn_code; - -/* Similar, but counts all expressions in the MD file; used for - error messages. */ - -static int next_index; - -/* Record the highest depth we ever have so we know how many variables to - allocate in each subroutine we make. */ - -static int max_depth; - -/* This table contains a list of the rtl codes that can possibly match a - predicate defined in recog.c. The function `not_both_true' uses it to - deduce that there are no expressions that can be matches by certain pairs - of tree nodes. Also, if a predicate can match only one code, we can - hardwire that code into the node testing the predicate. */ - -static struct pred_table -{ - const char *name; - RTX_CODE codes[NUM_RTX_CODE]; -} preds[] - = {{"general_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF, SUBREG, REG, MEM}}, -#ifdef PREDICATE_CODES - PREDICATE_CODES -#endif - {"address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF, SUBREG, REG, MEM, PLUS, MINUS, MULT}}, - {"register_operand", {SUBREG, REG}}, - {"scratch_operand", {SCRATCH, REG}}, - {"immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF}}, - {"const_int_operand", {CONST_INT}}, - {"const_double_operand", {CONST_INT, CONST_DOUBLE}}, - {"nonimmediate_operand", {SUBREG, REG, MEM}}, - {"nonmemory_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF, SUBREG, REG}}, - {"push_operand", {MEM}}, - {"pop_operand", {MEM}}, - {"memory_operand", {SUBREG, MEM}}, - {"indirect_operand", {SUBREG, MEM}}, - {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU}}, - {"mode_independent_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF, SUBREG, REG, MEM}}}; - -#define NUM_KNOWN_PREDS (sizeof preds / sizeof preds[0]) - -static struct decision_head make_insn_sequence PROTO((rtx, enum routine_type)); -static struct decision *add_to_sequence PROTO((rtx, struct decision_head *, - const char *)); -static int not_both_true PROTO((struct decision *, struct decision *, - int)); -static int position_merit PROTO((struct decision *, enum machine_mode, - enum rtx_code)); -static struct decision_head merge_trees PROTO((struct decision_head, - struct decision_head)); -static int break_out_subroutines PROTO((struct decision_head, - enum routine_type, int)); -static void write_subroutine PROTO((struct decision *, enum routine_type)); -static void write_tree_1 PROTO((struct decision *, const char *, - struct decision *, enum routine_type)); -static void print_code PROTO((enum rtx_code)); -static int same_codes PROTO((struct decision *, enum rtx_code)); -static void clear_codes PROTO((struct decision *)); -static int same_modes PROTO((struct decision *, enum machine_mode)); -static void clear_modes PROTO((struct decision *)); -static void write_tree PROTO((struct decision *, const char *, - struct decision *, int, - enum routine_type)); -static void change_state PROTO((const char *, const char *, int)); -void fatal PVPROTO((const char *, ...)) - ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN; -void fancy_abort PROTO((void)) ATTRIBUTE_NORETURN; - -/* Construct and return a sequence of decisions - that will recognize INSN. - - TYPE says what type of routine we are recognizing (RECOG or SPLIT). */ - -static struct decision_head -make_insn_sequence (insn, type) - rtx insn; - enum routine_type type; -{ - rtx x; - char *c_test = XSTR (insn, type == RECOG ? 2 : 1); - struct decision *last; - struct decision_head head; - - { - static char *last_real_name = "insn"; - static int last_real_code = 0; - char *name; - - if (insn_name_ptr_size <= next_insn_code) - { - int new_size; - new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512); - insn_name_ptr = - (char **) xrealloc (insn_name_ptr, sizeof(char *) * new_size); - bzero ((PTR)(insn_name_ptr + insn_name_ptr_size), - sizeof(char *) * (new_size - insn_name_ptr_size)); - insn_name_ptr_size = new_size; - } - - name = XSTR (insn, 0); - if (!name || name[0] == '\0') - { - name = xmalloc (strlen (last_real_name) + 10); - sprintf (name, "%s+%d", last_real_name, - next_insn_code - last_real_code); - } - else - { - last_real_name = name; - last_real_code = next_insn_code; - } - - insn_name_ptr[next_insn_code] = name; - } - - if (XVECLEN (insn, type == RECOG) == 1) - x = XVECEXP (insn, type == RECOG, 0); - else - { - x = rtx_alloc (PARALLEL); - XVEC (x, 0) = XVEC (insn, type == RECOG); - PUT_MODE (x, VOIDmode); - } - - last = add_to_sequence (x, &head, ""); - - if (c_test[0]) - last->c_test = c_test; - last->insn_code_number = next_insn_code; - last->num_clobbers_to_add = 0; - - /* If this is not a DEFINE_SPLIT and X is a PARALLEL, see if it ends with a - group of CLOBBERs of (hard) registers or MATCH_SCRATCHes. If so, set up - to recognize the pattern without these CLOBBERs. */ - - if (type == RECOG && GET_CODE (x) == PARALLEL) - { - int i; - - for (i = XVECLEN (x, 0); i > 0; i--) - if (GET_CODE (XVECEXP (x, 0, i - 1)) != CLOBBER - || (GET_CODE (XEXP (XVECEXP (x, 0, i - 1), 0)) != REG - && GET_CODE (XEXP (XVECEXP (x, 0, i - 1), 0)) != MATCH_SCRATCH)) - break; - - if (i != XVECLEN (x, 0)) - { - rtx new; - struct decision_head clobber_head; - - if (i == 1) - new = XVECEXP (x, 0, 0); - else - { - int j; - - new = rtx_alloc (PARALLEL); - XVEC (new, 0) = rtvec_alloc (i); - for (j = i - 1; j >= 0; j--) - XVECEXP (new, 0, j) = XVECEXP (x, 0, j); - } - - last = add_to_sequence (new, &clobber_head, ""); - - if (c_test[0]) - last->c_test = c_test; - last->insn_code_number = next_insn_code; - last->num_clobbers_to_add = XVECLEN (x, 0) - i; - - head = merge_trees (head, clobber_head); - } - } - - next_insn_code++; - - if (type == SPLIT) - /* Define the subroutine we will call below and emit in genemit. */ - printf ("extern rtx gen_split_%d ();\n", last->insn_code_number); - - return head; -} - -/* Create a chain of nodes to verify that an rtl expression matches - PATTERN. - - LAST is a pointer to the listhead in the previous node in the chain (or - in the calling function, for the first node). - - POSITION is the string representing the current position in the insn. - - A pointer to the final node in the chain is returned. */ - -static struct decision * -add_to_sequence (pattern, last, position) - rtx pattern; - struct decision_head *last; - const 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 size_t i; - int depth = strlen (position); - int len; - - if (depth > max_depth) - max_depth = depth; - - new->number = next_number++; - new->position = xstrdup (position); - new->ignore_code = 0; - new->ignore_mode = 0; - new->enforce_mode = 1; - new->retest_code = new->retest_mode = 0; - new->veclen = 0; - new->test_elt_zero_int = 0; - new->test_elt_one_int = 0; - new->test_elt_zero_wide = 0; - new->elt_zero_int = 0; - new->elt_one_int = 0; - new->elt_zero_wide = 0; - new->tests = 0; - new->pred = -1; - new->c_test = 0; - new->success.first = new->success.last = 0; - new->insn_code_number = -1; - new->num_clobbers_to_add = 0; - new->next = 0; - new->prev = 0; - new->afterward = 0; - new->opno = -1; - new->dupno = -1; - new->label_needed = 0; - new->subroutine_number = 0; - - this = new; - - last->first = last->last = new; - - newpos = (char *) alloca (depth + 2); - strcpy (newpos, position); - newpos[depth + 1] = 0; - - restart: - - new->mode = GET_MODE (pattern); - new->code = code = GET_CODE (pattern); - - switch (code) - { - case MATCH_OPERAND: - case MATCH_SCRATCH: - case MATCH_OPERATOR: - case MATCH_PARALLEL: - case MATCH_INSN2: - new->opno = XINT (pattern, 0); - new->code = (code == MATCH_PARALLEL ? PARALLEL : UNKNOWN); - new->enforce_mode = 0; - - if (code == MATCH_SCRATCH) - new->tests = "scratch_operand"; - else - new->tests = XSTR (pattern, 1); - - if (*new->tests == 0) - new->tests = 0; - - /* See if we know about this predicate and save its number. If we do, - and it only accepts one code, note that fact. The predicate - `const_int_operand' only tests for a CONST_INT, so if we do so we - can avoid calling it at all. - - Finally, if we know that the predicate does not allow CONST_INT, we - know that the only way the predicate can match is if the modes match - (here we use the kludge of relying on the fact that "address_operand" - accepts CONST_INT; otherwise, it would have to be a special case), - so we can test the mode (but we need not). This fact should - considerably simplify the generated code. */ - - if (new->tests) - { - for (i = 0; i < NUM_KNOWN_PREDS; i++) - if (! strcmp (preds[i].name, new->tests)) - { - int j; - int allows_const_int = 0; - - new->pred = i; - - if (preds[i].codes[1] == 0 && new->code == UNKNOWN) - { - new->code = preds[i].codes[0]; - if (! strcmp ("const_int_operand", new->tests)) - new->tests = 0, new->pred = -1; - } - - for (j = 0; j < NUM_RTX_CODE && preds[i].codes[j] != 0; j++) - if (preds[i].codes[j] == CONST_INT) - allows_const_int = 1; - - if (! allows_const_int) - new->enforce_mode = new->ignore_mode= 1; - - break; - } - -#ifdef PREDICATE_CODES - /* If the port has a list of the predicates it uses but omits - one, warn. */ - if (i == NUM_KNOWN_PREDS) - fprintf (stderr, "Warning: `%s' not in PREDICATE_CODES\n", - new->tests); -#endif - } - - if (code == MATCH_OPERATOR || code == MATCH_PARALLEL) - { - for (i = 0; i < (size_t) XVECLEN (pattern, 2); i++) - { - newpos[depth] = i + (code == MATCH_OPERATOR ? '0': 'a'); - new = add_to_sequence (XVECEXP (pattern, 2, i), - &new->success, newpos); - } - } - - return new; - - case MATCH_OP_DUP: - new->opno = XINT (pattern, 0); - new->dupno = XINT (pattern, 0); - new->code = UNKNOWN; - new->tests = 0; - for (i = 0; i < (size_t) XVECLEN (pattern, 1); i++) - { - newpos[depth] = i + '0'; - new = add_to_sequence (XVECEXP (pattern, 1, i), - &new->success, newpos); - } - return new; - - case MATCH_DUP: - case MATCH_PAR_DUP: - new->dupno = XINT (pattern, 0); - new->code = UNKNOWN; - new->enforce_mode = 0; - return new; - - case ADDRESS: - pattern = XEXP (pattern, 0); - goto restart; - - case SET: - /* The operands of a SET must have the same mode unless one is VOIDmode. */ - if (GET_MODE (SET_SRC (pattern)) != VOIDmode - && GET_MODE (SET_DEST (pattern)) != VOIDmode - && GET_MODE (SET_SRC (pattern)) != GET_MODE (SET_DEST (pattern)) - /* The mode of an ADDRESS_OPERAND is the mode of the memory reference, - not the mode of the address. */ - && ! (GET_CODE (SET_SRC (pattern)) == MATCH_OPERAND - && ! strcmp (XSTR (SET_SRC (pattern), 1), "address_operand"))) - { - print_rtl (stderr, pattern); - fputc ('\n', stderr); - fatal ("mode mismatch in SET"); - } - newpos[depth] = '0'; - new = add_to_sequence (SET_DEST (pattern), &new->success, newpos); - this->success.first->enforce_mode = 1; - newpos[depth] = '1'; - new = add_to_sequence (SET_SRC (pattern), &new->success, newpos); - - /* If set are setting CC0 from anything other than a COMPARE, we - must enforce the mode so that we do not produce ambiguous insns. */ - if (GET_CODE (SET_DEST (pattern)) == CC0 - && GET_CODE (SET_SRC (pattern)) != COMPARE) - this->success.first->enforce_mode = 1; - return new; - - case SIGN_EXTEND: - case ZERO_EXTEND: - case STRICT_LOW_PART: - newpos[depth] = '0'; - new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos); - this->success.first->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->success, newpos); - this->success.first->enforce_mode = 1; - return new; - - case ZERO_EXTRACT: - case SIGN_EXTRACT: - newpos[depth] = '0'; - new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos); - this->success.first->enforce_mode = 1; - newpos[depth] = '1'; - new = add_to_sequence (XEXP (pattern, 1), &new->success, newpos); - newpos[depth] = '2'; - new = add_to_sequence (XEXP (pattern, 2), &new->success, newpos); - return new; - - case EQ: case NE: case LE: case LT: case GE: case GT: - case LEU: case LTU: case GEU: case GTU: - /* If the first operand is (cc0), we don't have to do anything - special. */ - if (GET_CODE (XEXP (pattern, 0)) == CC0) - break; - - /* ... fall through ... */ - - case COMPARE: - /* Enforce the mode on the first operand to avoid ambiguous insns. */ - newpos[depth] = '0'; - new = add_to_sequence (XEXP (pattern, 0), &new->success, newpos); - this->success.first->enforce_mode = 1; - newpos[depth] = '1'; - new = add_to_sequence (XEXP (pattern, 1), &new->success, newpos); - return new; - - default: - break; - } - - fmt = GET_RTX_FORMAT (code); - len = GET_RTX_LENGTH (code); - for (i = 0; i < (size_t) len; i++) - { - newpos[depth] = '0' + i; - if (fmt[i] == 'e' || fmt[i] == 'u') - new = add_to_sequence (XEXP (pattern, i), &new->success, 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] == 'w' && i == 0) - { - this->test_elt_zero_wide = 1; - this->elt_zero_wide = XWINT (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->success, newpos); - } - } - else if (fmt[i] != '0') - abort (); - } - return new; -} - -/* Return 1 if we can prove that there is no RTL that can match both - D1 and D2. Otherwise, return 0 (it may be that there is an RTL that - can match both or just that we couldn't prove there wasn't such an RTL). - - TOPLEVEL is non-zero if we are to only look at the top level and not - recursively descend. */ - -static int -not_both_true (d1, d2, toplevel) - struct decision *d1, *d2; - int toplevel; -{ - struct decision *p1, *p2; - - /* If they are both to test modes and the modes are different, they aren't - both true. Similarly for codes, integer elements, and vector lengths. */ - - if ((d1->enforce_mode && d2->enforce_mode - && d1->mode != VOIDmode && d2->mode != VOIDmode && d1->mode != d2->mode) - || (d1->code != UNKNOWN && d2->code != UNKNOWN && d1->code != d2->code) - || (d1->test_elt_zero_int && d2->test_elt_zero_int - && d1->elt_zero_int != d2->elt_zero_int) - || (d1->test_elt_one_int && d2->test_elt_one_int - && d1->elt_one_int != d2->elt_one_int) - || (d1->test_elt_zero_wide && d2->test_elt_zero_wide - && d1->elt_zero_wide != d2->elt_zero_wide) - || (d1->veclen && d2->veclen && d1->veclen != d2->veclen)) - return 1; - - /* If either is a wild-card MATCH_OPERAND without a predicate, it can match - absolutely anything, so we can't say that no intersection is possible. - This case is detected by having a zero TESTS field with a code of - UNKNOWN. */ - - if ((d1->tests == 0 && d1->code == UNKNOWN) - || (d2->tests == 0 && d2->code == UNKNOWN)) - return 0; - - /* If either has a predicate that we know something about, set things up so - that D1 is the one that always has a known predicate. Then see if they - have any codes in common. */ - - if (d1->pred >= 0 || d2->pred >= 0) - { - int i, j; - - if (d2->pred >= 0) - p1 = d1, d1 = d2, d2 = p1; - - /* If D2 tests an explicit code, see if it is in the list of valid codes - for D1's predicate. */ - if (d2->code != UNKNOWN) - { - for (i = 0; i < NUM_RTX_CODE && preds[d1->pred].codes[i] != 0; i++) - if (preds[d1->pred].codes[i] == d2->code) - break; - - if (preds[d1->pred].codes[i] == 0) - return 1; - } - - /* Otherwise see if the predicates have any codes in common. */ - - else if (d2->pred >= 0) - { - for (i = 0; i < NUM_RTX_CODE && preds[d1->pred].codes[i] != 0; i++) - { - for (j = 0; j < NUM_RTX_CODE; j++) - if (preds[d2->pred].codes[j] == 0 - || preds[d2->pred].codes[j] == preds[d1->pred].codes[i]) - break; - - if (preds[d2->pred].codes[j] != 0) - break; - } - - if (preds[d1->pred].codes[i] == 0) - return 1; - } - } - - /* If we got here, we can't prove that D1 and D2 cannot both be true. - If we are only to check the top level, return 0. Otherwise, see if - we can prove that all choices in both successors are mutually - exclusive. If either does not have any successors, we can't prove - they can't both be true. */ - - if (toplevel || d1->success.first == 0 || d2->success.first == 0) - return 0; - - for (p1 = d1->success.first; p1; p1 = p1->next) - for (p2 = d2->success.first; p2; p2 = p2->next) - if (! not_both_true (p1, p2, 0)) - return 0; - - return 1; -} - -/* Assuming that we can reorder all the alternatives at a specific point in - the tree (see discussion in merge_trees), we would prefer an ordering of - nodes where groups of consecutive nodes test the same mode and, within each - mode, groups of nodes test the same code. With this order, we can - construct nested switch statements, the inner one to test the code and - the outer one to test the mode. - - We would like to list nodes testing for specific codes before those - that test predicates to avoid unnecessary function calls. Similarly, - tests for specific modes should precede nodes that allow any mode. - - This function returns the merit (with 0 being the best) of inserting - a test involving the specified MODE and CODE after node P. If P is - zero, we are to determine the merit of inserting the test at the front - of the list. */ - -static int -position_merit (p, mode, code) - struct decision *p; - enum machine_mode mode; - enum rtx_code code; -{ - enum machine_mode p_mode; - - /* The only time the front of the list is anything other than the worst - position is if we are testing a mode that isn't VOIDmode. */ - if (p == 0) - return mode == VOIDmode ? 3 : 2; - - p_mode = p->enforce_mode ? p->mode : VOIDmode; - - /* The best case is if the codes and modes both match. */ - if (p_mode == mode && p->code== code) - return 0; - - /* If the codes don't match, the next best case is if the modes match. - In that case, the best position for this node depends on whether - we are testing for a specific code or not. If we are, the best place - is after some other test for an explicit code and our mode or after - the last test in the previous mode if every test in our mode is for - an unknown code. - - If we are testing for UNKNOWN, then the next best case is at the end of - our mode. */ - - if ((code != UNKNOWN - && ((p_mode == mode && p->code != UNKNOWN) - || (p_mode != mode && p->next - && (p->next->enforce_mode ? p->next->mode : VOIDmode) == mode - && (p->next->code == UNKNOWN)))) - || (code == UNKNOWN && p_mode == mode - && (p->next == 0 - || (p->next->enforce_mode ? p->next->mode : VOIDmode) != mode))) - return 1; - - /* The third best case occurs when nothing is testing MODE. If MODE - is not VOIDmode, then the third best case is after something of any - mode that is not VOIDmode. If we are testing VOIDmode, the third best - place is the end of the list. */ - - if (p_mode != mode - && ((mode != VOIDmode && p_mode != VOIDmode) - || (mode == VOIDmode && p->next == 0))) - return 2; - - /* Otherwise, we have the worst case. */ - return 3; -} - -/* Merge two decision tree listheads OLDH and ADDH, - modifying OLDH destructively, and return the merged tree. */ - -static struct decision_head -merge_trees (oldh, addh) - register struct decision_head oldh, addh; -{ - struct decision *add, *next; - - if (oldh.first == 0) - return addh; - - if (addh.first == 0) - return oldh; - - /* If we are adding things at different positions, something is wrong. */ - if (strcmp (oldh.first->position, addh.first->position)) - abort (); - - for (add = addh.first; add; add = next) - { - enum machine_mode add_mode = add->enforce_mode ? add->mode : VOIDmode; - struct decision *best_position = 0; - int best_merit = 4; - struct decision *old; - - next = add->next; - - /* The semantics of pattern matching state that the tests are done in - the order given in the MD file so that if an insn matches two - patterns, the first one will be used. However, in practice, most, - if not all, patterns are unambiguous so that their order is - independent. In that case, we can merge identical tests and - group all similar modes and codes together. - - Scan starting from the end of OLDH until we reach a point - where we reach the head of the list or where we pass a pattern - that could also be true if NEW is true. If we find an identical - pattern, we can merge them. Also, record the last node that tests - the same code and mode and the last one that tests just the same mode. - - If we have no match, place NEW after the closest match we found. */ - - for (old = oldh.last; old; old = old->prev) - { - int our_merit; - - /* If we don't have anything to test except an additional test, - do not consider the two nodes equal. If we did, the test below - would cause an infinite recursion. */ - if (old->tests == 0 && old->test_elt_zero_int == 0 - && old->test_elt_one_int == 0 && old->veclen == 0 - && old->test_elt_zero_wide == 0 - && old->dupno == -1 && old->mode == VOIDmode - && old->code == UNKNOWN - && (old->c_test != 0 || add->c_test != 0)) - ; - - else if ((old->tests == add->tests - || (old->pred >= 0 && old->pred == add->pred) - || (old->tests && add->tests - && !strcmp (old->tests, add->tests))) - && 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->test_elt_zero_wide == add->test_elt_zero_wide - && old->elt_zero_wide == add->elt_zero_wide - && old->veclen == add->veclen - && old->dupno == add->dupno - && old->opno == add->opno - && old->code == add->code - && old->enforce_mode == add->enforce_mode - && old->mode == add->mode) - { - /* If the additional test is not the same, split both nodes - into nodes that just contain all things tested before the - additional test and nodes that contain the additional test - and actions when it is true. This optimization is important - because of the case where we have almost identical patterns - with different tests on target flags. */ - - if (old->c_test != add->c_test - && ! (old->c_test && add->c_test - && !strcmp (old->c_test, add->c_test))) - { - if (old->insn_code_number >= 0 || old->opno >= 0) - { - struct decision *split - = (struct decision *) xmalloc (sizeof (struct decision)); - - memcpy (split, old, sizeof (struct decision)); - - old->success.first = old->success.last = split; - old->c_test = 0; - old->opno = -1; - old->insn_code_number = -1; - old->num_clobbers_to_add = 0; - - split->number = next_number++; - split->next = split->prev = 0; - split->mode = VOIDmode; - split->code = UNKNOWN; - split->veclen = 0; - split->test_elt_zero_int = 0; - split->test_elt_one_int = 0; - split->test_elt_zero_wide = 0; - split->tests = 0; - split->pred = -1; - split->dupno = -1; - } - - if (add->insn_code_number >= 0 || add->opno >= 0) - { - struct decision *split - = (struct decision *) xmalloc (sizeof (struct decision)); - - memcpy (split, add, sizeof (struct decision)); - - add->success.first = add->success.last = split; - add->c_test = 0; - add->opno = -1; - add->insn_code_number = -1; - add->num_clobbers_to_add = 0; - - split->number = next_number++; - split->next = split->prev = 0; - split->mode = VOIDmode; - split->code = UNKNOWN; - split->veclen = 0; - split->test_elt_zero_int = 0; - split->test_elt_one_int = 0; - split->test_elt_zero_wide = 0; - split->tests = 0; - split->pred = -1; - split->dupno = -1; - } - } - - if (old->insn_code_number >= 0 && add->insn_code_number >= 0) - { - /* If one node is for a normal insn and the second is - for the base insn with clobbers stripped off, the - second node should be ignored. */ - - if (old->num_clobbers_to_add == 0 - && add->num_clobbers_to_add > 0) - /* Nothing to do here. */ - ; - else if (old->num_clobbers_to_add > 0 - && add->num_clobbers_to_add == 0) - { - /* In this case, replace OLD with ADD. */ - old->insn_code_number = add->insn_code_number; - old->num_clobbers_to_add = 0; - } - else - fatal ("Two actions at one point in tree for insns \"%s\" (%d) and \"%s\" (%d)", - insn_name_ptr[old->insn_code_number], - old->insn_code_number, - insn_name_ptr[add->insn_code_number], - add->insn_code_number); - } - - if (old->insn_code_number == -1) - old->insn_code_number = add->insn_code_number; - old->success = merge_trees (old->success, add->success); - add = 0; - break; - } - - /* Unless we have already found the best possible insert point, - see if this position is better. If so, record it. */ - - if (best_merit != 0 - && ((our_merit = position_merit (old, add_mode, add->code)) - < best_merit)) - best_merit = our_merit, best_position = old; - - if (! not_both_true (old, add, 0)) - break; - } - - /* If ADD was duplicate, we are done. */ - if (add == 0) - continue; - - /* Otherwise, find the best place to insert ADD. Normally this is - BEST_POSITION. However, if we went all the way to the top of - the list, it might be better to insert at the top. */ - - if (best_position == 0) - abort (); - - if (old == 0 - && position_merit (NULL_PTR, add_mode, add->code) < best_merit) - { - add->prev = 0; - add->next = oldh.first; - oldh.first->prev = add; - oldh.first = add; - } - - else - { - add->prev = best_position; - add->next = best_position->next; - best_position->next = add; - if (best_position == oldh.last) - oldh.last = add; - else - add->next->prev = add; - } - } - - return oldh; -} - -/* Count the number of subnodes of HEAD. If the number is high enough, - make the first node in HEAD start a separate subroutine in the C code - that is generated. - - TYPE gives the type of routine we are writing. - - INITIAL is non-zero if this is the highest-level node. We never write - it out here. */ - -static int -break_out_subroutines (head, type, initial) - struct decision_head head; - enum routine_type type; - int initial; -{ - int size = 0; - struct decision *sub; - - for (sub = head.first; sub; sub = sub->next) - size += 1 + break_out_subroutines (sub->success, type, 0); - - if (size > SUBROUTINE_THRESHOLD && ! initial) - { - head.first->subroutine_number = ++next_subroutine_number; - write_subroutine (head.first, type); - size = 1; - } - return size; -} - -/* Write out a subroutine of type TYPE to do comparisons starting at node - TREE. */ - -static void -write_subroutine (tree, type) - struct decision *tree; - enum routine_type type; -{ - int i; - - if (type == SPLIT) - printf ("rtx\nsplit"); - else - printf ("int\nrecog"); - - if (tree != 0 && tree->subroutine_number > 0) - printf ("_%d", tree->subroutine_number); - else if (type == SPLIT) - printf ("_insns"); - - printf (" (x0, insn"); - if (type == RECOG) - printf (", pnum_clobbers"); - - printf (")\n"); - printf (" register rtx x0;\n rtx insn ATTRIBUTE_UNUSED;\n"); - if (type == RECOG) - printf (" int *pnum_clobbers ATTRIBUTE_UNUSED;\n"); - - printf ("{\n"); - printf (" register rtx *ro = &recog_operand[0];\n"); - - printf (" register rtx "); - for (i = 1; i < max_depth; i++) - printf ("x%d ATTRIBUTE_UNUSED, ", i); - - printf ("x%d ATTRIBUTE_UNUSED;\n", max_depth); - printf (" %s tem ATTRIBUTE_UNUSED;\n", type == SPLIT ? "rtx" : "int"); - write_tree (tree, "", NULL_PTR, 1, type); - printf (" ret0: return %d;\n}\n\n", type == SPLIT ? 0 : -1); -} - -/* This table is used to indent the recog_* functions when we are inside - conditions or switch statements. We only support small indentations - and always indent at least two spaces. */ - -static const char *indents[] - = {" ", " ", " ", " ", " ", " ", " ", " ", - "\t", "\t ", "\t ", "\t ", "\t ", "\t ", "\t ", - "\t\t", "\t\t ", "\t\t ", "\t\t ", "\t\t ", "\t\t "}; - -/* Write out C code to perform the decisions in TREE for a subroutine of - type TYPE. If all of the choices fail, branch to node AFTERWARD, if - non-zero, otherwise return. PREVPOS is the position of the node that - branched to this test. - - When we merged all alternatives, we tried to set up a convenient order. - Specifically, tests involving the same mode are all grouped together, - followed by a group that does not contain a mode test. Within each group - of the same mode, we also group tests with the same code, followed by a - group that does not test a code. - - Occasionally, we cannot arbitrarily reorder the tests so that multiple - sequence of groups as described above are present. - - We generate two nested switch statements, the outer statement for - testing modes, and the inner switch for testing RTX codes. It is - not worth optimizing cases when only a small number of modes or - codes is tested, since the compiler can do that when compiling the - resulting function. We do check for when every test is the same mode - or code. */ - -static void -write_tree_1 (tree, prevpos, afterward, type) - struct decision *tree; - const char *prevpos; - struct decision *afterward; - enum routine_type type; -{ - register struct decision *p, *p1; - register int depth = tree ? strlen (tree->position) : 0; - enum machine_mode switch_mode = VOIDmode; - RTX_CODE switch_code = UNKNOWN; - int uncond = 0; - char modemap[NUM_MACHINE_MODES]; - char codemap[NUM_RTX_CODE]; - int indent = 2; - int i; - - /* One tricky area is what is the exact state when we branch to a - node's label. There are two cases where we branch: when looking at - successors to a node, or when a set of tests fails. - - In the former case, we are always branching to the first node in a - decision list and we want all required tests to be performed. We - put the labels for such nodes in front of any switch or test statements. - These branches are done without updating the position to that of the - target node. - - In the latter case, we are branching to a node that is not the first - node in a decision list. We have already checked that it is possible - for both the node we originally tested at this level and the node we - are branching to to both match some pattern. That means that they - usually will be testing the same mode and code. So it is normally safe - for such labels to be inside switch statements, since the tests done - by virtue of arriving at that label will usually already have been - done. The exception is a branch from a node that does not test a - mode or code to one that does. In such cases, we set the `retest_mode' - or `retest_code' flags. That will ensure that we start a new switch - at that position and put the label before the switch. - - The branches in the latter case must set the position to that of the - target node. */ - - - printf ("\n"); - if (tree && tree->subroutine_number == 0) - { - OUTPUT_LABEL (" ", tree->number); - tree->label_needed = 0; - } - - if (tree) - { - change_state (prevpos, tree->position, 2); - prevpos = tree->position; - } - - for (p = tree; p; p = p->next) - { - enum machine_mode mode = p->enforce_mode ? p->mode : VOIDmode; - int need_bracket; - int wrote_bracket = 0; - int inner_indent; - - if (p->success.first == 0 && p->insn_code_number < 0) - abort (); - - /* Find the next alternative to p that might be true when p is true. - Test that one next if p's successors fail. */ - - for (p1 = p->next; p1 && not_both_true (p, p1, 1); p1 = p1->next) - ; - p->afterward = p1; - - if (p1) - { - if (mode == VOIDmode && p1->enforce_mode && p1->mode != VOIDmode) - p1->retest_mode = 1; - if (p->code == UNKNOWN && p1->code != UNKNOWN) - p1->retest_code = 1; - p1->label_needed = 1; - } - - /* If we have a different code or mode than the last node and - are in a switch on codes, we must either end the switch or - go to another case. We must also end the switch if this - node needs a label and to retest either the mode or code. */ - - if (switch_code != UNKNOWN - && (switch_code != p->code || switch_mode != mode - || (p->label_needed && (p->retest_mode || p->retest_code)))) - { - enum rtx_code code = p->code; - - /* If P is testing a predicate that we know about and we haven't - seen any of the codes that are valid for the predicate, we - can write a series of "case" statement, one for each possible - code. Since we are already in a switch, these redundant tests - are very cheap and will reduce the number of predicate called. */ - - if (p->pred >= 0) - { - for (i = 0; i < NUM_RTX_CODE && preds[p->pred].codes[i] != 0; i++) - if (codemap[(int) preds[p->pred].codes[i]]) - break; - - if (preds[p->pred].codes[i] == 0) - code = MATCH_OPERAND; - } - - if (code == UNKNOWN || codemap[(int) code] - || switch_mode != mode - || (p->label_needed && (p->retest_mode || p->retest_code))) - { - printf ("%s}\n", indents[indent - 2]); - switch_code = UNKNOWN; - indent -= 4; - } - else - { - if (! uncond) - printf ("%sbreak;\n", indents[indent]); - - if (code == MATCH_OPERAND) - { - for (i = 0; i < NUM_RTX_CODE && preds[p->pred].codes[i] != 0; i++) - { - printf ("%scase ", indents[indent - 2]); - print_code (preds[p->pred].codes[i]); - printf (":\n"); - codemap[(int) preds[p->pred].codes[i]] = 1; - } - } - else - { - printf ("%scase ", indents[indent - 2]); - print_code (code); - printf (":\n"); - codemap[(int) p->code] = 1; - } - - switch_code = code; - } - - uncond = 0; - } - - /* If we were previously in a switch on modes and now have a different - mode, end at least the case, and maybe end the switch if we are - not testing a mode or testing a mode whose case we already saw. */ - - if (switch_mode != VOIDmode - && (switch_mode != mode || (p->label_needed && p->retest_mode))) - { - if (mode == VOIDmode || modemap[(int) mode] - || (p->label_needed && p->retest_mode)) - { - printf ("%s}\n", indents[indent - 2]); - switch_mode = VOIDmode; - indent -= 4; - } - else - { - if (! uncond) - printf (" break;\n"); - printf (" case %smode:\n", GET_MODE_NAME (mode)); - switch_mode = mode; - modemap[(int) mode] = 1; - } - - uncond = 0; - } - - /* If we are about to write dead code, something went wrong. */ - if (! p->label_needed && uncond) - abort (); - - /* If we need a label and we will want to retest the mode or code at - that label, write the label now. We have already ensured that - things will be valid for the test. */ - - if (p->label_needed && (p->retest_mode || p->retest_code)) - { - OUTPUT_LABEL (indents[indent - 2], p->number); - p->label_needed = 0; - } - - uncond = 0; - - /* If we are not in any switches, see if we can shortcut things - by checking for identical modes and codes. */ - - if (switch_mode == VOIDmode && switch_code == UNKNOWN) - { - /* If p and its alternatives all want the same mode, - reject all others at once, first, then ignore the mode. */ - - if (mode != VOIDmode && p->next && same_modes (p, mode)) - { - printf (" if (GET_MODE (x%d) != %smode)\n", - depth, GET_MODE_NAME (p->mode)); - if (afterward) - { - printf (" {\n"); - change_state (p->position, afterward->position, 6); - printf (" goto L%d;\n }\n", afterward->number); - } - else - printf (" goto ret0;\n"); - clear_modes (p); - mode = VOIDmode; - } - - /* 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 (" {\n"); - change_state (p->position, afterward->position, indent + 4); - printf (" goto L%d;\n }\n", afterward->number); - } - else - printf (" goto ret0;\n"); - clear_codes (p); - } - } - - /* If we are not in a mode switch and we are testing for a specific - mode, start a mode switch unless we have just one node or the next - node is not testing a mode (we have already tested for the case of - more than one mode, but all of the same mode). */ - - if (switch_mode == VOIDmode && mode != VOIDmode && p->next != 0 - && p->next->enforce_mode && p->next->mode != VOIDmode) - { - memset (modemap, 0, sizeof modemap); - printf ("%sswitch (GET_MODE (x%d))\n", indents[indent], depth); - printf ("%s{\n", indents[indent + 2]); - indent += 4; - printf ("%sdefault:\n%sbreak;\n", indents[indent - 2], - indents[indent]); - printf ("%scase %smode:\n", indents[indent - 2], - GET_MODE_NAME (mode)); - modemap[(int) mode] = 1; - switch_mode = mode; - } - - /* Similarly for testing codes. */ - - if (switch_code == UNKNOWN && p->code != UNKNOWN && ! p->ignore_code - && p->next != 0 && p->next->code != UNKNOWN) - { - memset (codemap, 0, sizeof codemap); - printf ("%sswitch (GET_CODE (x%d))\n", indents[indent], depth); - printf ("%s{\n", indents[indent + 2]); - indent += 4; - printf ("%sdefault:\n%sbreak;\n", indents[indent - 2], - indents[indent]); - printf ("%scase ", indents[indent - 2]); - print_code (p->code); - printf (":\n"); - codemap[(int) p->code] = 1; - switch_code = p->code; - } - - /* Now that most mode and code tests have been done, we can write out - a label for an inner node, if we haven't already. */ - if (p->label_needed) - OUTPUT_LABEL (indents[indent - 2], p->number); - - inner_indent = indent; - - /* The only way we can have to do a mode or code test here is if - this node needs such a test but is the only node to be tested. - In that case, we won't have started a switch. Note that this is - the only way the switch and test modes can disagree. */ - - if ((mode != switch_mode && ! p->ignore_mode) - || (p->code != switch_code && p->code != UNKNOWN && ! p->ignore_code) - || p->test_elt_zero_int || p->test_elt_one_int - || p->test_elt_zero_wide || p->veclen - || p->dupno >= 0 || p->tests || p->num_clobbers_to_add) - { - printf ("%sif (", indents[indent]); - - if (mode != switch_mode && ! p->ignore_mode) - printf ("GET_MODE (x%d) == %smode && ", - depth, GET_MODE_NAME (mode)); - if (p->code != switch_code && p->code != UNKNOWN && ! p->ignore_code) - { - printf ("GET_CODE (x%d) == ", depth); - print_code (p->code); - printf (" && "); - } - - if (p->test_elt_zero_int) - printf ("XINT (x%d, 0) == %d && ", depth, p->elt_zero_int); - if (p->test_elt_one_int) - printf ("XINT (x%d, 1) == %d && ", depth, p->elt_one_int); - if (p->test_elt_zero_wide) - { - /* Set offset to 1 iff the number might get propagated to - unsigned long by ANSI C rules, else 0. - Prospective hosts are required to have at least 32 bit - ints, and integer constants in machine descriptions - must fit in 32 bit, thus it suffices to check only - for 1 << 31 . */ - HOST_WIDE_INT offset = p->elt_zero_wide == -2147483647 - 1; - printf ("XWINT (x%d, 0) == ", depth); - printf (HOST_WIDE_INT_PRINT_DEC, p->elt_zero_wide + offset); - printf ("%s && ", offset ? "-1" : ""); - } - if (p->veclen) - printf ("XVECLEN (x%d, 0) == %d && ", depth, p->veclen); - if (p->dupno >= 0) - printf ("rtx_equal_p (x%d, ro[%d]) && ", depth, p->dupno); - if (p->num_clobbers_to_add) - printf ("pnum_clobbers != 0 && "); - if (p->tests) - printf ("%s (x%d, %smode)", p->tests, depth, - GET_MODE_NAME (p->mode)); - else - printf ("1"); - - printf (")\n"); - inner_indent += 2; - } - else - uncond = 1; - - need_bracket = ! uncond; - - if (p->opno >= 0) - { - if (need_bracket) - { - printf ("%s{\n", indents[inner_indent]); - inner_indent += 2; - wrote_bracket = 1; - need_bracket = 0; - } - - printf ("%sro[%d] = x%d;\n", indents[inner_indent], p->opno, depth); - } - - if (p->c_test) - { - printf ("%sif (%s)\n", indents[inner_indent], p->c_test); - inner_indent += 2; - uncond = 0; - need_bracket = 1; - } - - if (p->insn_code_number >= 0) - { - if (type == SPLIT) - printf ("%sreturn gen_split_%d (operands);\n", - indents[inner_indent], p->insn_code_number); - else - { - if (p->num_clobbers_to_add) - { - if (need_bracket) - { - printf ("%s{\n", indents[inner_indent]); - inner_indent += 2; - } - - printf ("%s*pnum_clobbers = %d;\n", - indents[inner_indent], p->num_clobbers_to_add); - printf ("%sreturn %d;\n", - indents[inner_indent], p->insn_code_number); - - if (need_bracket) - { - inner_indent -= 2; - printf ("%s}\n", indents[inner_indent]); - } - } - else - printf ("%sreturn %d;\n", - indents[inner_indent], p->insn_code_number); - } - } - else - printf ("%sgoto L%d;\n", indents[inner_indent], - p->success.first->number); - - if (wrote_bracket) - printf ("%s}\n", indents[inner_indent - 2]); - } - - /* We have now tested all alternatives. End any switches we have open - and branch to the alternative node unless we know that we can't fall - through to the branch. */ - - if (switch_code != UNKNOWN) - { - printf ("%s}\n", indents[indent - 2]); - indent -= 4; - uncond = 0; - } - - if (switch_mode != VOIDmode) - { - printf ("%s}\n", indents[indent - 2]); - indent -= 4; - uncond = 0; - } - - if (indent != 2) - abort (); - - if (uncond) - return; - - if (afterward) - { - change_state (prevpos, afterward->position, 2); - printf (" goto L%d;\n", afterward->number); - } - else - printf (" goto ret0;\n"); -} - -static void -print_code (code) - enum 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); - } -} - -static int -same_codes (p, code) - register struct decision *p; - register enum rtx_code code; -{ - for (; p; p = p->next) - if (p->code != code) - return 0; - - return 1; -} - -static void -clear_codes (p) - register struct decision *p; -{ - for (; p; p = p->next) - p->ignore_code = 1; -} - -static int -same_modes (p, mode) - register struct decision *p; - register enum machine_mode mode; -{ - for (; p; p = p->next) - if ((p->enforce_mode ? p->mode : VOIDmode) != mode) - return 0; - - return 1; -} - -static void -clear_modes (p) - register struct decision *p; -{ - for (; p; p = p->next) - p->enforce_mode = 0; -} - -/* Write out the decision tree starting at TREE for a subroutine of type TYPE. - - PREVPOS is the position at the node that branched to this node. - - INITIAL is nonzero if this is the first node we are writing in a subroutine. - - If all nodes are false, branch to the node AFTERWARD. */ - -static void -write_tree (tree, prevpos, afterward, initial, type) - struct decision *tree; - const char *prevpos; - struct decision *afterward; - int initial; - enum routine_type type; -{ - register struct decision *p; - const char *name_prefix = (type == SPLIT ? "split" : "recog"); - const char *call_suffix = (type == SPLIT ? "" : ", pnum_clobbers"); - - if (! initial && tree->subroutine_number > 0) - { - OUTPUT_LABEL (" ", tree->number); - - if (afterward) - { - printf (" tem = %s_%d (x0, insn%s);\n", - name_prefix, tree->subroutine_number, call_suffix); - if (type == SPLIT) - printf (" if (tem != 0) return tem;\n"); - else - printf (" if (tem >= 0) return tem;\n"); - change_state (tree->position, afterward->position, 2); - printf (" goto L%d;\n", afterward->number); - } - else - printf (" return %s_%d (x0, insn%s);\n", - name_prefix, tree->subroutine_number, call_suffix); - return; - } - - write_tree_1 (tree, prevpos, afterward, type); - - for (p = tree; p; p = p->next) - if (p->success.first) - write_tree (p->success.first, p->position, - p->afterward ? p->afterward : afterward, 0, type); -} - - -/* Assuming that the state of argument is denoted by OLDPOS, take whatever - actions are necessary to move to NEWPOS. - - INDENT says how many blanks to place at the front of lines. */ - -static void -change_state (oldpos, newpos, indent) - const char *oldpos; - const char *newpos; - int indent; -{ - 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] >= 'a' && newpos[depth] <= 'z') - printf ("%sx%d = XVECEXP (x%d, 0, %d);\n", - indents[indent], depth + 1, depth, newpos[depth] - 'a'); - else - printf ("%sx%d = XEXP (x%d, %c);\n", - indents[indent], depth + 1, depth, newpos[depth]); - ++depth; - } -} - -char * -xstrdup (input) - const char *input; -{ - register size_t len = strlen (input) + 1; - register char *output = xmalloc (len); - memcpy (output, input, len); - return output; -} - -PTR -xrealloc (old, size) - PTR old; - size_t size; -{ - register PTR ptr; - if (old) - ptr = (PTR) realloc (old, size); - else - ptr = (PTR) malloc (size); - if (!ptr) - fatal ("virtual memory exhausted"); - return ptr; -} - -PTR -xmalloc (size) - size_t size; -{ - register PTR val = (PTR) malloc (size); - - if (val == 0) - fatal ("virtual memory exhausted"); - return val; -} - -void -fatal VPROTO ((const char *format, ...)) -{ -#ifndef ANSI_PROTOTYPES - const char *format; -#endif - va_list ap; - - VA_START (ap, format); - -#ifndef ANSI_PROTOTYPES - format = va_arg (ap, const char *); -#endif - - fprintf (stderr, "genrecog: "); - vfprintf (stderr, format, ap); - va_end (ap); - fprintf (stderr, "\n"); - fprintf (stderr, "after %d definitions\n", next_index); - exit (FATAL_EXIT_CODE); -} - -/* More 'friendly' abort that prints the line and file. - config.h can #define abort fancy_abort if you like that sort of thing. */ - -void -fancy_abort () -{ - fatal ("Internal gcc abort."); -} - -int -main (argc, argv) - int argc; - char **argv; -{ - rtx desc; - struct decision_head recog_tree; - struct decision_head split_tree; - FILE *infile; - register int c; - - obstack_init (rtl_obstack); - recog_tree.first = recog_tree.last = split_tree.first = split_tree.last = 0; - - 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; - next_index = 0; - - printf ("/* Generated automatically by the program `genrecog'\n\ -from the machine description file `md'. */\n\n"); - - printf ("#include \"config.h\"\n"); - printf ("#include \"system.h\"\n"); - printf ("#include \"rtl.h\"\n"); - printf ("#include \"insn-config.h\"\n"); - printf ("#include \"recog.h\"\n"); - printf ("#include \"real.h\"\n"); - printf ("#include \"output.h\"\n"); - printf ("#include \"flags.h\"\n"); - printf ("\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) - recog_tree = merge_trees (recog_tree, - make_insn_sequence (desc, RECOG)); - else if (GET_CODE (desc) == DEFINE_SPLIT) - split_tree = merge_trees (split_tree, - make_insn_sequence (desc, SPLIT)); - if (GET_CODE (desc) == DEFINE_PEEPHOLE - || GET_CODE (desc) == DEFINE_EXPAND) - next_insn_code++; - next_index++; - } - - 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 various\n\ - insn_* tables, such as insn_templates, insn_outfun, and insn_n_operands\n\ - (found in insn-output.c).\n\n"); - printf (" The third argument to recog is an optional pointer to an int.\n\ - If present, recog will accept a pattern if it matches except for\n\ - missing CLOBBER expressions at the end. In that case, the value\n\ - pointed to by the optional pointer will be set to the number of\n\ - CLOBBERs that need to be added (it should be initialized to zero by\n\ - the caller). If it is set nonzero, the caller should allocate a\n\ - PARALLEL of the appropriate size, copy the initial entries, and call\n\ - add_clobbers (found in insn-emit.c) to fill in the CLOBBERs."); - - if (split_tree.first) - printf ("\n\n The function split_insns returns 0 if the rtl could not\n\ - be split or the split rtl in a SEQUENCE if it can be."); - - printf ("*/\n\n"); - - printf ("#define operands recog_operand\n\n"); - - next_subroutine_number = 0; - break_out_subroutines (recog_tree, RECOG, 1); - write_subroutine (recog_tree.first, RECOG); - - next_subroutine_number = 0; - break_out_subroutines (split_tree, SPLIT, 1); - write_subroutine (split_tree.first, SPLIT); - - fflush (stdout); - exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); - /* NOTREACHED */ - return 0; -} |