+ rtx x;
+ const char *c_test = XSTR (insn, type == RECOG ? 2 : 1);
+ int truth = maybe_eval_c_test (c_test);
+ struct decision *last;
+ struct decision_test *test, **place;
+ struct decision_head head;
+ char c_test_pos[2];
+
+ /* We should never see an insn whose C test is false at compile time. */
+ gcc_assert (truth);
+
+ c_test_pos[0] = '\0';
+ if (type == PEEPHOLE2)
+ {
+ int i, j;
+
+ /* peephole2 gets special treatment:
+ - X always gets an outer parallel even if it's only one entry
+ - we remove all traces of outer-level match_scratch and match_dup
+ expressions here. */
+ x = rtx_alloc (PARALLEL);
+ PUT_MODE (x, VOIDmode);
+ XVEC (x, 0) = rtvec_alloc (XVECLEN (insn, 0));
+ for (i = j = 0; i < XVECLEN (insn, 0); i++)
+ {
+ rtx tmp = XVECEXP (insn, 0, i);
+ if (GET_CODE (tmp) != MATCH_SCRATCH && GET_CODE (tmp) != MATCH_DUP)
+ {
+ XVECEXP (x, 0, j) = tmp;
+ j++;
+ }
+ }
+ XVECLEN (x, 0) = j;
+
+ c_test_pos[0] = 'A' + j - 1;
+ c_test_pos[1] = '\0';
+ }
+ else 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);
+ }
+
+ validate_pattern (x, insn, NULL_RTX, 0);
+
+ memset(&head, 0, sizeof(head));
+ last = add_to_sequence (x, &head, "", type, 1);
+
+ /* Find the end of the test chain on the last node. */
+ for (test = last->tests; test->next; test = test->next)
+ continue;
+ place = &test->next;
+
+ /* Skip the C test if it's known to be true at compile time. */
+ if (truth == -1)
+ {
+ /* Need a new node if we have another test to add. */
+ if (test->type == DT_accept_op)
+ {
+ last = new_decision (c_test_pos, &last->success);
+ place = &last->tests;
+ }
+ test = new_decision_test (DT_c_test, &place);
+ test->u.c_test = c_test;
+ }
+
+ test = new_decision_test (DT_accept_insn, &place);
+ test->u.insn.code_number = next_insn_code;
+ test->u.insn.lineno = pattern_lineno;
+ test->u.insn.num_clobbers_to_add = 0;
+
+ switch (type)
+ {
+ case RECOG:
+ /* If this is a DEFINE_INSN 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 (GET_CODE (x) == PARALLEL)
+ {
+ int i;
+
+ /* Find the last non-clobber in the parallel. */
+ for (i = XVECLEN (x, 0); i > 0; i--)
+ {
+ rtx y = XVECEXP (x, 0, i - 1);
+ if (GET_CODE (y) != CLOBBER
+ || (!REG_P (XEXP (y, 0))
+ && GET_CODE (XEXP (y, 0)) != MATCH_SCRATCH))
+ break;
+ }
+
+ if (i != XVECLEN (x, 0))
+ {
+ rtx new_rtx;
+ struct decision_head clobber_head;
+
+ /* Build a similar insn without the clobbers. */
+ if (i == 1)
+ new_rtx = XVECEXP (x, 0, 0);
+ else
+ {
+ int j;
+
+ new_rtx = rtx_alloc (PARALLEL);
+ XVEC (new_rtx, 0) = rtvec_alloc (i);
+ for (j = i - 1; j >= 0; j--)
+ XVECEXP (new_rtx, 0, j) = XVECEXP (x, 0, j);
+ }
+
+ /* Recognize it. */
+ memset (&clobber_head, 0, sizeof(clobber_head));
+ last = add_to_sequence (new_rtx, &clobber_head, "", type, 1);
+
+ /* Find the end of the test chain on the last node. */
+ for (test = last->tests; test->next; test = test->next)
+ continue;
+
+ /* We definitely have a new test to add -- create a new
+ node if needed. */
+ place = &test->next;
+ if (test->type == DT_accept_op)
+ {
+ last = new_decision ("", &last->success);
+ place = &last->tests;
+ }
+
+ /* Skip the C test if it's known to be true at compile
+ time. */
+ if (truth == -1)
+ {
+ test = new_decision_test (DT_c_test, &place);
+ test->u.c_test = c_test;
+ }
+
+ test = new_decision_test (DT_accept_insn, &place);
+ test->u.insn.code_number = next_insn_code;
+ test->u.insn.lineno = pattern_lineno;
+ test->u.insn.num_clobbers_to_add = XVECLEN (x, 0) - i;
+
+ merge_trees (&head, &clobber_head);
+ }
+ }
+ break;
+
+ case SPLIT:
+ /* Define the subroutine we will call below and emit in genemit. */
+ printf ("extern rtx gen_split_%d (rtx, rtx *);\n", next_insn_code);
+ break;
+
+ case PEEPHOLE2:
+ /* Define the subroutine we will call below and emit in genemit. */
+ printf ("extern rtx gen_peephole2_%d (rtx, rtx *);\n",
+ next_insn_code);
+ break;
+ }
+
+ return head;
+}
+
+static void
+process_tree (struct decision_head *head, enum routine_type subroutine_type)
+{
+ if (head->first == NULL)
+ {
+ /* We can elide peephole2_insns, but not recog or split_insns. */
+ if (subroutine_type == PEEPHOLE2)
+ return;
+ }
+ else
+ {
+ factor_tests (head);
+
+ next_subroutine_number = 0;
+ break_out_subroutines (head, 1);
+ find_afterward (head, NULL);
+
+ /* We run this after find_afterward, because find_afterward needs
+ the redundant DT_mode tests on predicates to determine whether
+ two tests can both be true or not. */
+ simplify_tests(head);
+
+ write_subroutines (head, subroutine_type);
+ }
+
+ write_subroutine (head, subroutine_type);