📄 genrecog.c
字号:
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 intbreak_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 voidwrite_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;\n"); if (type == RECOG) printf (" int *pnum_clobbers;\n"); printf ("{\n"); printf (" register rtx *ro = &recog_operand[0];\n"); printf (" register rtx "); for (i = 1; i < max_depth; i++) printf ("x%d, ", i); printf ("x%d;\n", max_depth); printf (" %s tem;\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 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 voidwrite_tree_1 (tree, prevpos, afterward, type) struct decision *tree; 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 be 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) { printf (" L%d:\n", 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)) { printf ("%sL%d:\n", 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) { mybzero (modemap, sizeof modemap); printf ("%sswitch (GET_MODE (x%d))\n", indents[indent], depth); printf ("%s{\n", indents[indent + 2]); indent += 4; 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) { mybzero (codemap, sizeof codemap); printf ("%sswitch (GET_CODE (x%d))\n", indents[indent], depth); printf ("%s{\n", indents[indent + 2]); indent += 4; 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) printf ("%sL%d:\n", 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 (#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT "XWINT (x%d, 0) == %d%s && ",#else "XWINT (x%d, 0) == %ld%s && ",#endif depth, p->elt_zero_wide + offset, offset ? "-1" : ""); } if (p->veclen)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -