aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/gcc/genrecog.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/genrecog.c')
-rw-r--r--gcc-4.2.1-5666.3/gcc/genrecog.c2929
1 files changed, 0 insertions, 2929 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/genrecog.c b/gcc-4.2.1-5666.3/gcc/genrecog.c
deleted file mode 100644
index a65137ab3..000000000
--- a/gcc-4.2.1-5666.3/gcc/genrecog.c
+++ /dev/null
@@ -1,2929 +0,0 @@
-/* Generate code from machine description to recognize rtl as insns.
- Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
-
- This file is part of GCC.
-
- GCC 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.
-
- GCC 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 GCC; see the file COPYING. If not, write to the Free
- Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, 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 as an INSN list.
-
- This program also generates the function `peephole2_insns', which
- returns 0 if the rtl could not be matched. If there was a match,
- the new rtl is returned in an INSN list, and LAST_INSN will point
- to the last recognized insn in the old sequence. */
-
-#include "bconfig.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "rtl.h"
-#include "errors.h"
-#include "gensupport.h"
-
-#define OUTPUT_LABEL(INDENT_STRING, LABEL_NUMBER) \
- printf("%sL%d: ATTRIBUTE_UNUSED_LABEL\n", (INDENT_STRING), (LABEL_NUMBER))
-
-/* A listhead of decision trees. The alternatives to a node are kept
- in a doubly-linked list so we can easily add nodes to the proper
- place when merging. */
-
-struct decision_head
-{
- struct decision *first;
- struct decision *last;
-};
-
-/* A single test. The two accept types aren't tests per-se, but
- their equality (or lack thereof) does affect tree merging so
- it is convenient to keep them here. */
-
-struct decision_test
-{
- /* A linked list through the tests attached to a node. */
- struct decision_test *next;
-
- /* These types are roughly in the order in which we'd like to test them. */
- enum decision_type
- {
- DT_num_insns,
- DT_mode, DT_code, DT_veclen,
- DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide, DT_elt_zero_wide_safe,
- DT_const_int,
- DT_veclen_ge, DT_dup, DT_pred, DT_c_test,
- DT_accept_op, DT_accept_insn
- } type;
-
- union
- {
- int num_insns; /* Number if insn in a define_peephole2. */
- enum machine_mode mode; /* Machine mode of node. */
- RTX_CODE code; /* Code to test. */
-
- struct
- {
- const char *name; /* Predicate to call. */
- const struct pred_data *data;
- /* Optimization hints for this predicate. */
- enum machine_mode mode; /* Machine mode for node. */
- } pred;
-
- const char *c_test; /* Additional test to perform. */
- int veclen; /* Length of vector. */
- int dup; /* Number of operand to compare against. */
- HOST_WIDE_INT intval; /* Value for XINT for XWINT. */
- int opno; /* Operand number matched. */
-
- struct {
- int code_number; /* Insn number matched. */
- int lineno; /* Line number of the insn. */
- int num_clobbers_to_add; /* Number of CLOBBERs to be added. */
- } insn;
- } u;
-};
-
-/* Data structure for decision tree for recognizing legitimate insns. */
-
-struct decision
-{
- struct decision_head success; /* Nodes to test on success. */
- 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. */
-
- const char *position; /* String denoting position in pattern. */
-
- struct decision_test *tests; /* The tests for this node. */
-
- int number; /* Node number, used for labels */
- int subroutine_number; /* Number of subroutine this node starts */
- int need_label; /* Label needs to be output. */
-};
-
-#define SUBROUTINE_THRESHOLD 100
-
-static int next_subroutine_number;
-
-/* We can write three types of subroutines: One for insn recognition,
- one to split insns, and one for peephole-type optimizations. This
- defines which type is being written. */
-
-enum routine_type {
- RECOG, SPLIT, PEEPHOLE2
-};
-
-#define IS_SPLIT(X) ((X) != RECOG)
-
-/* Next available node number for tree nodes. */
-
-static int next_number;
-
-/* Next number to use as an insn_code. */
-
-static int next_insn_code;
-
-/* Record the highest depth we ever have so we know how many variables to
- allocate in each subroutine we make. */
-
-static int max_depth;
-
-/* The line number of the start of the pattern currently being processed. */
-static int pattern_lineno;
-
-/* Count of errors. */
-static int error_count;
-
-/* Predicate handling.
-
- We construct from the machine description a table mapping each
- predicate to a list of the rtl codes it can possibly match. The
- function 'maybe_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.
-
- Some predicates are flagged as special. validate_pattern will not
- warn about modeless match_operand expressions if they have a
- special predicate. Predicates that allow only constants are also
- treated as special, for this purpose.
-
- validate_pattern will warn about predicates that allow non-lvalues
- when they appear in destination operands.
-
- Calculating the set of rtx codes that can possibly be accepted by a
- predicate expression EXP requires a three-state logic: any given
- subexpression may definitively accept a code C (Y), definitively
- reject a code C (N), or may have an indeterminate effect (I). N
- and I is N; Y or I is Y; Y and I, N or I are both I. Here are full
- truth tables.
-
- a b a&b a|b
- Y Y Y Y
- N Y N Y
- N N N N
- I Y I Y
- I N N I
- I I I I
-
- We represent Y with 1, N with 0, I with 2. If any code is left in
- an I state by the complete expression, we must assume that that
- code can be accepted. */
-
-#define N 0
-#define Y 1
-#define I 2
-
-#define TRISTATE_AND(a,b) \
- ((a) == I ? ((b) == N ? N : I) : \
- (b) == I ? ((a) == N ? N : I) : \
- (a) && (b))
-
-#define TRISTATE_OR(a,b) \
- ((a) == I ? ((b) == Y ? Y : I) : \
- (b) == I ? ((a) == Y ? Y : I) : \
- (a) || (b))
-
-#define TRISTATE_NOT(a) \
- ((a) == I ? I : !(a))
-
-/* 0 means no warning about that code yet, 1 means warned. */
-static char did_you_mean_codes[NUM_RTX_CODE];
-
-/* Recursively calculate the set of rtx codes accepted by the
- predicate expression EXP, writing the result to CODES. */
-static void
-compute_predicate_codes (rtx exp, char codes[NUM_RTX_CODE])
-{
- char op0_codes[NUM_RTX_CODE];
- char op1_codes[NUM_RTX_CODE];
- char op2_codes[NUM_RTX_CODE];
- int i;
-
- switch (GET_CODE (exp))
- {
- case AND:
- compute_predicate_codes (XEXP (exp, 0), op0_codes);
- compute_predicate_codes (XEXP (exp, 1), op1_codes);
- for (i = 0; i < NUM_RTX_CODE; i++)
- codes[i] = TRISTATE_AND (op0_codes[i], op1_codes[i]);
- break;
-
- case IOR:
- compute_predicate_codes (XEXP (exp, 0), op0_codes);
- compute_predicate_codes (XEXP (exp, 1), op1_codes);
- for (i = 0; i < NUM_RTX_CODE; i++)
- codes[i] = TRISTATE_OR (op0_codes[i], op1_codes[i]);
- break;
- case NOT:
- compute_predicate_codes (XEXP (exp, 0), op0_codes);
- for (i = 0; i < NUM_RTX_CODE; i++)
- codes[i] = TRISTATE_NOT (op0_codes[i]);
- break;
-
- case IF_THEN_ELSE:
- /* a ? b : c accepts the same codes as (a & b) | (!a & c). */
- compute_predicate_codes (XEXP (exp, 0), op0_codes);
- compute_predicate_codes (XEXP (exp, 1), op1_codes);
- compute_predicate_codes (XEXP (exp, 2), op2_codes);
- for (i = 0; i < NUM_RTX_CODE; i++)
- codes[i] = TRISTATE_OR (TRISTATE_AND (op0_codes[i], op1_codes[i]),
- TRISTATE_AND (TRISTATE_NOT (op0_codes[i]),
- op2_codes[i]));
- break;
-
- case MATCH_CODE:
- /* MATCH_CODE allows a specified list of codes. However, if it
- does not apply to the top level of the expression, it does not
- constrain the set of codes for the top level. */
- if (XSTR (exp, 1)[0] != '\0')
- {
- memset (codes, Y, NUM_RTX_CODE);
- break;
- }
-
- memset (codes, N, NUM_RTX_CODE);
- {
- const char *next_code = XSTR (exp, 0);
- const char *code;
-
- if (*next_code == '\0')
- {
- message_with_line (pattern_lineno, "empty match_code expression");
- error_count++;
- break;
- }
-
- while ((code = scan_comma_elt (&next_code)) != 0)
- {
- size_t n = next_code - code;
- int found_it = 0;
-
- for (i = 0; i < NUM_RTX_CODE; i++)
- if (!strncmp (code, GET_RTX_NAME (i), n)
- && GET_RTX_NAME (i)[n] == '\0')
- {
- codes[i] = Y;
- found_it = 1;
- break;
- }
- if (!found_it)
- {
- message_with_line (pattern_lineno, "match_code \"%.*s\" matches nothing",
- (int) n, code);
- error_count ++;
- for (i = 0; i < NUM_RTX_CODE; i++)
- if (!strncasecmp (code, GET_RTX_NAME (i), n)
- && GET_RTX_NAME (i)[n] == '\0'
- && !did_you_mean_codes[i])
- {
- did_you_mean_codes[i] = 1;
- message_with_line (pattern_lineno, "(did you mean \"%s\"?)", GET_RTX_NAME (i));
- }
- }
-
- }
- }
- break;
-
- case MATCH_OPERAND:
- /* MATCH_OPERAND disallows the set of codes that the named predicate
- disallows, and is indeterminate for the codes that it does allow. */
- {
- struct pred_data *p = lookup_predicate (XSTR (exp, 1));
- if (!p)
- {
- message_with_line (pattern_lineno,
- "reference to unknown predicate '%s'",
- XSTR (exp, 1));
- error_count++;
- break;
- }
- for (i = 0; i < NUM_RTX_CODE; i++)
- codes[i] = p->codes[i] ? I : N;
- }
- break;
-
-
- case MATCH_TEST:
- /* (match_test WHATEVER) is completely indeterminate. */
- memset (codes, I, NUM_RTX_CODE);
- break;
-
- default:
- message_with_line (pattern_lineno,
- "'%s' cannot be used in a define_predicate expression",
- GET_RTX_NAME (GET_CODE (exp)));
- error_count++;
- memset (codes, I, NUM_RTX_CODE);
- break;
- }
-}
-
-#undef TRISTATE_OR
-#undef TRISTATE_AND
-#undef TRISTATE_NOT
-
-/* Process a define_predicate expression: compute the set of predicates
- that can be matched, and record this as a known predicate. */
-static void
-process_define_predicate (rtx desc)
-{
- struct pred_data *pred = xcalloc (sizeof (struct pred_data), 1);
- char codes[NUM_RTX_CODE];
- bool seen_one = false;
- int i;
-
- pred->name = XSTR (desc, 0);
- if (GET_CODE (desc) == DEFINE_SPECIAL_PREDICATE)
- pred->special = 1;
-
- compute_predicate_codes (XEXP (desc, 1), codes);
-
- for (i = 0; i < NUM_RTX_CODE; i++)
- if (codes[i] != N)
- {
- pred->codes[i] = true;
- if (GET_RTX_CLASS (i) != RTX_CONST_OBJ)
- pred->allows_non_const = true;
- if (i != REG
- && i != SUBREG
- && i != MEM
- && i != CONCAT
- && i != PARALLEL
- && i != STRICT_LOW_PART)
- pred->allows_non_lvalue = true;
-
- if (seen_one)
- pred->singleton = UNKNOWN;
- else
- {
- pred->singleton = i;
- seen_one = true;
- }
- }
- add_predicate (pred);
-}
-#undef I
-#undef N
-#undef Y
-
-
-static struct decision *new_decision
- (const char *, struct decision_head *);
-static struct decision_test *new_decision_test
- (enum decision_type, struct decision_test ***);
-static rtx find_operand
- (rtx, int, rtx);
-static rtx find_matching_operand
- (rtx, int);
-static void validate_pattern
- (rtx, rtx, rtx, int);
-static struct decision *add_to_sequence
- (rtx, struct decision_head *, const char *, enum routine_type, int);
-
-static int maybe_both_true_2
- (struct decision_test *, struct decision_test *);
-static int maybe_both_true_1
- (struct decision_test *, struct decision_test *);
-static int maybe_both_true
- (struct decision *, struct decision *, int);
-
-static int nodes_identical_1
- (struct decision_test *, struct decision_test *);
-static int nodes_identical
- (struct decision *, struct decision *);
-static void merge_accept_insn
- (struct decision *, struct decision *);
-static void merge_trees
- (struct decision_head *, struct decision_head *);
-
-static void factor_tests
- (struct decision_head *);
-static void simplify_tests
- (struct decision_head *);
-static int break_out_subroutines
- (struct decision_head *, int);
-static void find_afterward
- (struct decision_head *, struct decision *);
-
-static void change_state
- (const char *, const char *, const char *);
-static void print_code
- (enum rtx_code);
-static void write_afterward
- (struct decision *, struct decision *, const char *);
-static struct decision *write_switch
- (struct decision *, int);
-static void write_cond
- (struct decision_test *, int, enum routine_type);
-static void write_action
- (struct decision *, struct decision_test *, int, int,
- struct decision *, enum routine_type);
-static int is_unconditional
- (struct decision_test *, enum routine_type);
-static int write_node
- (struct decision *, int, enum routine_type);
-static void write_tree_1
- (struct decision_head *, int, enum routine_type);
-static void write_tree
- (struct decision_head *, const char *, enum routine_type, int);
-static void write_subroutine
- (struct decision_head *, enum routine_type);
-static void write_subroutines
- (struct decision_head *, enum routine_type);
-static void write_header
- (void);
-
-static struct decision_head make_insn_sequence
- (rtx, enum routine_type);
-static void process_tree
- (struct decision_head *, enum routine_type);
-
-static void debug_decision_0
- (struct decision *, int, int);
-static void debug_decision_1
- (struct decision *, int);
-static void debug_decision_2
- (struct decision_test *);
-extern void debug_decision
- (struct decision *);
-extern void debug_decision_list
- (struct decision *);
-
-/* Create a new node in sequence after LAST. */
-
-static struct decision *
-new_decision (const char *position, struct decision_head *last)
-{
- struct decision *new = xcalloc (1, sizeof (struct decision));
-
- new->success = *last;
- new->position = xstrdup (position);
- new->number = next_number++;
-
- last->first = last->last = new;
- return new;
-}
-
-/* Create a new test and link it in at PLACE. */
-
-static struct decision_test *
-new_decision_test (enum decision_type type, struct decision_test ***pplace)
-{
- struct decision_test **place = *pplace;
- struct decision_test *test;
-
- test = XNEW (struct decision_test);
- test->next = *place;
- test->type = type;
- *place = test;
-
- place = &test->next;
- *pplace = place;
-
- return test;
-}
-
-/* Search for and return operand N, stop when reaching node STOP. */
-
-static rtx
-find_operand (rtx pattern, int n, rtx stop)
-{
- const char *fmt;
- RTX_CODE code;
- int i, j, len;
- rtx r;
-
- if (pattern == stop)
- return stop;
-
- code = GET_CODE (pattern);
- if ((code == MATCH_SCRATCH
- || code == MATCH_OPERAND
- || code == MATCH_OPERATOR
- || code == MATCH_PARALLEL)
- && XINT (pattern, 0) == n)
- return pattern;
-
- fmt = GET_RTX_FORMAT (code);
- len = GET_RTX_LENGTH (code);
- for (i = 0; i < len; i++)
- {
- switch (fmt[i])
- {
- case 'e': case 'u':
- if ((r = find_operand (XEXP (pattern, i), n, stop)) != NULL_RTX)
- return r;
- break;
-
- case 'V':
- if (! XVEC (pattern, i))
- break;
- /* Fall through. */
-
- case 'E':
- for (j = 0; j < XVECLEN (pattern, i); j++)
- if ((r = find_operand (XVECEXP (pattern, i, j), n, stop))
- != NULL_RTX)
- return r;
- break;
-
- case 'i': case 'w': case '0': case 's':
- break;
-
- default:
- gcc_unreachable ();
- }
- }
-
- return NULL;
-}
-
-/* Search for and return operand M, such that it has a matching
- constraint for operand N. */
-
-static rtx
-find_matching_operand (rtx pattern, int n)
-{
- const char *fmt;
- RTX_CODE code;
- int i, j, len;
- rtx r;
-
- code = GET_CODE (pattern);
- if (code == MATCH_OPERAND
- && (XSTR (pattern, 2)[0] == '0' + n
- || (XSTR (pattern, 2)[0] == '%'
- && XSTR (pattern, 2)[1] == '0' + n)))
- return pattern;
-
- fmt = GET_RTX_FORMAT (code);
- len = GET_RTX_LENGTH (code);
- for (i = 0; i < len; i++)
- {
- switch (fmt[i])
- {
- case 'e': case 'u':
- if ((r = find_matching_operand (XEXP (pattern, i), n)))
- return r;
- break;
-
- case 'V':
- if (! XVEC (pattern, i))
- break;
- /* Fall through. */
-
- case 'E':
- for (j = 0; j < XVECLEN (pattern, i); j++)
- if ((r = find_matching_operand (XVECEXP (pattern, i, j), n)))
- return r;
- break;
-
- case 'i': case 'w': case '0': case 's':
- break;
-
- default:
- gcc_unreachable ();
- }
- }
-
- return NULL;
-}
-
-
-/* Check for various errors in patterns. SET is nonnull for a destination,
- and is the complete set pattern. SET_CODE is '=' for normal sets, and
- '+' within a context that requires in-out constraints. */
-
-static void
-validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
-{
- const char *fmt;
- RTX_CODE code;
- size_t i, len;
- int j;
-
- code = GET_CODE (pattern);
- switch (code)
- {
- case MATCH_SCRATCH:
- return;
- case MATCH_DUP:
- case MATCH_OP_DUP:
- case MATCH_PAR_DUP:
- if (find_operand (insn, XINT (pattern, 0), pattern) == pattern)
- {
- message_with_line (pattern_lineno,
- "operand %i duplicated before defined",
- XINT (pattern, 0));
- error_count++;
- }
- break;
- case MATCH_OPERAND:
- case MATCH_OPERATOR:
- {
- const char *pred_name = XSTR (pattern, 1);
- const struct pred_data *pred;
- const char *c_test;
-
- if (GET_CODE (insn) == DEFINE_INSN)
- c_test = XSTR (insn, 2);
- else
- c_test = XSTR (insn, 1);
-
- if (pred_name[0] != 0)
- {
- pred = lookup_predicate (pred_name);
- if (!pred)
- message_with_line (pattern_lineno,
- "warning: unknown predicate '%s'",
- pred_name);
- }
- else
- pred = 0;
-
- if (code == MATCH_OPERAND)
- {
- const char constraints0 = XSTR (pattern, 2)[0];
-
- /* In DEFINE_EXPAND, DEFINE_SPLIT, and DEFINE_PEEPHOLE2, we
- don't use the MATCH_OPERAND constraint, only the predicate.
- This is confusing to folks doing new ports, so help them
- not make the mistake. */
- if (GET_CODE (insn) == DEFINE_EXPAND
- || GET_CODE (insn) == DEFINE_SPLIT
- || GET_CODE (insn) == DEFINE_PEEPHOLE2)
- {
- if (constraints0)
- message_with_line (pattern_lineno,
- "warning: constraints not supported in %s",
- rtx_name[GET_CODE (insn)]);
- }
-
- /* A MATCH_OPERAND that is a SET should have an output reload. */
- else if (set && constraints0)
- {
- if (set_code == '+')
- {
- if (constraints0 == '+')
- ;
- /* If we've only got an output reload for this operand,
- we'd better have a matching input operand. */
- else if (constraints0 == '='
- && find_matching_operand (insn, XINT (pattern, 0)))
- ;
- else
- {
- message_with_line (pattern_lineno,
- "operand %d missing in-out reload",
- XINT (pattern, 0));
- error_count++;
- }
- }
- else if (constraints0 != '=' && constraints0 != '+')
- {
- message_with_line (pattern_lineno,
- "operand %d missing output reload",
- XINT (pattern, 0));
- error_count++;
- }
- }
- }
-
- /* Allowing non-lvalues in destinations -- particularly CONST_INT --
- while not likely to occur at runtime, results in less efficient
- code from insn-recog.c. */
- if (set && pred && pred->allows_non_lvalue)
- message_with_line (pattern_lineno,
- "warning: destination operand %d "
- "allows non-lvalue",
- XINT (pattern, 0));
-
- /* A modeless MATCH_OPERAND can be handy when we can check for
- multiple modes in the c_test. In most other cases, it is a
- mistake. Only DEFINE_INSN is eligible, since SPLIT and
- PEEP2 can FAIL within the output pattern. Exclude special
- predicates, which check the mode themselves. Also exclude
- predicates that allow only constants. Exclude the SET_DEST
- of a call instruction, as that is a common idiom. */
-
- if (GET_MODE (pattern) == VOIDmode
- && code == MATCH_OPERAND
- && GET_CODE (insn) == DEFINE_INSN
- && pred
- && !pred->special
- && pred->allows_non_const
- && strstr (c_test, "operands") == NULL
- && ! (set
- && GET_CODE (set) == SET
- && GET_CODE (SET_SRC (set)) == CALL))
- message_with_line (pattern_lineno,
- "warning: operand %d missing mode?",
- XINT (pattern, 0));
- return;
- }
-
- case SET:
- {
- enum machine_mode dmode, smode;
- rtx dest, src;
-
- dest = SET_DEST (pattern);
- src = SET_SRC (pattern);
-
- /* STRICT_LOW_PART is a wrapper. Its argument is the real
- destination, and it's mode should match the source. */
- if (GET_CODE (dest) == STRICT_LOW_PART)
- dest = XEXP (dest, 0);
-
- /* Find the referent for a DUP. */
-
- if (GET_CODE (dest) == MATCH_DUP
- || GET_CODE (dest) == MATCH_OP_DUP
- || GET_CODE (dest) == MATCH_PAR_DUP)
- dest = find_operand (insn, XINT (dest, 0), NULL);
-
- if (GET_CODE (src) == MATCH_DUP
- || GET_CODE (src) == MATCH_OP_DUP
- || GET_CODE (src) == MATCH_PAR_DUP)
- src = find_operand (insn, XINT (src, 0), NULL);
-
- dmode = GET_MODE (dest);
- smode = GET_MODE (src);
-
- /* The mode of an ADDRESS_OPERAND is the mode of the memory
- reference, not the mode of the address. */
- if (GET_CODE (src) == MATCH_OPERAND
- && ! strcmp (XSTR (src, 1), "address_operand"))
- ;
-
- /* The operands of a SET must have the same mode unless one
- is VOIDmode. */
- else if (dmode != VOIDmode && smode != VOIDmode && dmode != smode)
- {
- message_with_line (pattern_lineno,
- "mode mismatch in set: %smode vs %smode",
- GET_MODE_NAME (dmode), GET_MODE_NAME (smode));
- error_count++;
- }
-
- /* If only one of the operands is VOIDmode, and PC or CC0 is
- not involved, it's probably a mistake. */
- else if (dmode != smode
- && GET_CODE (dest) != PC
- && GET_CODE (dest) != CC0
- && GET_CODE (src) != PC
- && GET_CODE (src) != CC0
- && GET_CODE (src) != CONST_INT)
- {
- const char *which;
- which = (dmode == VOIDmode ? "destination" : "source");
- message_with_line (pattern_lineno,
- "warning: %s missing a mode?", which);
- }
-
- if (dest != SET_DEST (pattern))
- validate_pattern (dest, insn, pattern, '=');
- validate_pattern (SET_DEST (pattern), insn, pattern, '=');
- validate_pattern (SET_SRC (pattern), insn, NULL_RTX, 0);
- return;
- }
-
- case CLOBBER:
- validate_pattern (SET_DEST (pattern), insn, pattern, '=');
- return;
-
- case ZERO_EXTRACT:
- validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0);
- validate_pattern (XEXP (pattern, 1), insn, NULL_RTX, 0);
- validate_pattern (XEXP (pattern, 2), insn, NULL_RTX, 0);
- return;
-
- case STRICT_LOW_PART:
- validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0);
- return;
-
- case LABEL_REF:
- if (GET_MODE (XEXP (pattern, 0)) != VOIDmode)
- {
- message_with_line (pattern_lineno,
- "operand to label_ref %smode not VOIDmode",
- GET_MODE_NAME (GET_MODE (XEXP (pattern, 0))));
- error_count++;
- }
- break;
-
- default:
- break;
- }
-
- fmt = GET_RTX_FORMAT (code);
- len = GET_RTX_LENGTH (code);
- for (i = 0; i < len; i++)
- {
- switch (fmt[i])
- {
- case 'e': case 'u':
- validate_pattern (XEXP (pattern, i), insn, NULL_RTX, 0);
- break;
-
- case 'E':
- for (j = 0; j < XVECLEN (pattern, i); j++)
- validate_pattern (XVECEXP (pattern, i, j), insn, NULL_RTX, 0);
- break;
-
- case 'i': case 'w': case '0': case 's':
- break;
-
- default:
- gcc_unreachable ();
- }
- }
-}
-
-/* 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.
-
- INSN_TYPE is the type of insn for which we are emitting code.
-
- A pointer to the final node in the chain is returned. */
-
-static struct decision *
-add_to_sequence (rtx pattern, struct decision_head *last, const char *position,
- enum routine_type insn_type, int top)
-{
- RTX_CODE code;
- struct decision *this, *sub;
- struct decision_test *test;
- struct decision_test **place;
- char *subpos;
- size_t i;
- const char *fmt;
- int depth = strlen (position);
- int len;
- enum machine_mode mode;
-
- if (depth > max_depth)
- max_depth = depth;
-
- subpos = xmalloc (depth + 2);
- strcpy (subpos, position);
- subpos[depth + 1] = 0;
-
- sub = this = new_decision (position, last);
- place = &this->tests;
-
- restart:
- mode = GET_MODE (pattern);
- code = GET_CODE (pattern);
-
- switch (code)
- {
- case PARALLEL:
- /* Toplevel peephole pattern. */
- if (insn_type == PEEPHOLE2 && top)
- {
- int num_insns;
-
- /* Check we have sufficient insns. This avoids complications
- because we then know peep2_next_insn never fails. */
- num_insns = XVECLEN (pattern, 0);
- if (num_insns > 1)
- {
- test = new_decision_test (DT_num_insns, &place);
- test->u.num_insns = num_insns;
- last = &sub->success;
- }
- else
- {
- /* We don't need the node we just created -- unlink it. */
- last->first = last->last = NULL;
- }
-
- for (i = 0; i < (size_t) XVECLEN (pattern, 0); i++)
- {
- /* Which insn we're looking at is represented by A-Z. We don't
- ever use 'A', however; it is always implied. */
-
- subpos[depth] = (i > 0 ? 'A' + i : 0);
- sub = add_to_sequence (XVECEXP (pattern, 0, i),
- last, subpos, insn_type, 0);
- last = &sub->success;
- }
- goto ret;
- }
-
- /* Else nothing special. */
- break;
-
- case MATCH_PARALLEL:
- /* The explicit patterns within a match_parallel enforce a minimum
- length on the vector. The match_parallel predicate may allow
- for more elements. We do need to check for this minimum here
- or the code generated to match the internals may reference data
- beyond the end of the vector. */
- test = new_decision_test (DT_veclen_ge, &place);
- test->u.veclen = XVECLEN (pattern, 2);
- /* Fall through. */
-
- case MATCH_OPERAND:
- case MATCH_SCRATCH:
- case MATCH_OPERATOR:
- {
- RTX_CODE was_code = code;
- const char *pred_name;
- bool allows_const_int = true;
-
- if (code == MATCH_SCRATCH)
- {
- pred_name = "scratch_operand";
- code = UNKNOWN;
- }
- else
- {
- pred_name = XSTR (pattern, 1);
- if (code == MATCH_PARALLEL)
- code = PARALLEL;
- else
- code = UNKNOWN;
- }
-
- if (pred_name[0] != 0)
- {
- const struct pred_data *pred;
-
- test = new_decision_test (DT_pred, &place);
- test->u.pred.name = pred_name;
- test->u.pred.mode = mode;
-
- /* See if we know about this predicate.
- If we do, remember it for use below.
-
- We can optimize the generated code a little if either
- (a) the predicate only accepts one code, or (b) the
- predicate does not allow CONST_INT, in which case it
- can match only if the modes match. */
- pred = lookup_predicate (pred_name);
- if (pred)
- {
- test->u.pred.data = pred;
- allows_const_int = pred->codes[CONST_INT];
- if (was_code == MATCH_PARALLEL
- && pred->singleton != PARALLEL)
- message_with_line (pattern_lineno,
- "predicate '%s' used in match_parallel "
- "does not allow only PARALLEL", pred->name);
- else
- code = pred->singleton;
- }
- else
- message_with_line (pattern_lineno,
- "warning: unknown predicate '%s' in '%s' expression",
- pred_name, GET_RTX_NAME (was_code));
- }
-
- /* Can't enforce a mode if we allow const_int. */
- if (allows_const_int)
- mode = VOIDmode;
-
- /* Accept the operand, i.e. record it in `operands'. */
- test = new_decision_test (DT_accept_op, &place);
- test->u.opno = XINT (pattern, 0);
-
- if (was_code == MATCH_OPERATOR || was_code == MATCH_PARALLEL)
- {
- char base = (was_code == MATCH_OPERATOR ? '0' : 'a');
- for (i = 0; i < (size_t) XVECLEN (pattern, 2); i++)
- {
- subpos[depth] = i + base;
- sub = add_to_sequence (XVECEXP (pattern, 2, i),
- &sub->success, subpos, insn_type, 0);
- }
- }
- goto fini;
- }
-
- case MATCH_OP_DUP:
- code = UNKNOWN;
-
- test = new_decision_test (DT_dup, &place);
- test->u.dup = XINT (pattern, 0);
-
- test = new_decision_test (DT_accept_op, &place);
- test->u.opno = XINT (pattern, 0);
-
- for (i = 0; i < (size_t) XVECLEN (pattern, 1); i++)
- {
- subpos[depth] = i + '0';
- sub = add_to_sequence (XVECEXP (pattern, 1, i),
- &sub->success, subpos, insn_type, 0);
- }
- goto fini;
-
- case MATCH_DUP:
- case MATCH_PAR_DUP:
- code = UNKNOWN;
-
- test = new_decision_test (DT_dup, &place);
- test->u.dup = XINT (pattern, 0);
- goto fini;
-
- case ADDRESS:
- pattern = XEXP (pattern, 0);
- goto restart;
-
- default:
- break;
- }
-
- fmt = GET_RTX_FORMAT (code);
- len = GET_RTX_LENGTH (code);
-
- /* Do tests against the current node first. */
- for (i = 0; i < (size_t) len; i++)
- {
- if (fmt[i] == 'i')
- {
- gcc_assert (i < 2);
-
- if (!i)
- {
- test = new_decision_test (DT_elt_zero_int, &place);
- test->u.intval = XINT (pattern, i);
- }
- else
- {
- test = new_decision_test (DT_elt_one_int, &place);
- test->u.intval = XINT (pattern, i);
- }
- }
- else if (fmt[i] == 'w')
- {
- /* If this value actually fits in an int, we can use a switch
- statement here, so indicate that. */
- enum decision_type type
- = ((int) XWINT (pattern, i) == XWINT (pattern, i))
- ? DT_elt_zero_wide_safe : DT_elt_zero_wide;
-
- gcc_assert (!i);
-
- test = new_decision_test (type, &place);
- test->u.intval = XWINT (pattern, i);
- }
- else if (fmt[i] == 'E')
- {
- gcc_assert (!i);
-
- test = new_decision_test (DT_veclen, &place);
- test->u.veclen = XVECLEN (pattern, i);
- }
- }
-
- /* Now test our sub-patterns. */
- for (i = 0; i < (size_t) len; i++)
- {
- switch (fmt[i])
- {
- case 'e': case 'u':
- subpos[depth] = '0' + i;
- sub = add_to_sequence (XEXP (pattern, i), &sub->success,
- subpos, insn_type, 0);
- break;
-
- case 'E':
- {
- int j;
- for (j = 0; j < XVECLEN (pattern, i); j++)
- {
- subpos[depth] = 'a' + j;
- sub = add_to_sequence (XVECEXP (pattern, i, j),
- &sub->success, subpos, insn_type, 0);
- }
- break;
- }
-
- case 'i': case 'w':
- /* Handled above. */
- break;
- case '0':
- break;
-
- default:
- gcc_unreachable ();
- }
- }
-
- fini:
- /* Insert nodes testing mode and code, if they're still relevant,
- before any of the nodes we may have added above. */
- if (code != UNKNOWN)
- {
- place = &this->tests;
- test = new_decision_test (DT_code, &place);
- test->u.code = code;
- }
-
- if (mode != VOIDmode)
- {
- place = &this->tests;
- test = new_decision_test (DT_mode, &place);
- test->u.mode = mode;
- }
-
- /* If we didn't insert any tests or accept nodes, hork. */
- gcc_assert (this->tests);
-
- ret:
- free (subpos);
- return sub;
-}
-
-/* A subroutine of maybe_both_true; examines only one test.
- Returns > 0 for "definitely both true" and < 0 for "maybe both true". */
-
-static int
-maybe_both_true_2 (struct decision_test *d1, struct decision_test *d2)
-{
- if (d1->type == d2->type)
- {
- switch (d1->type)
- {
- case DT_num_insns:
- if (d1->u.num_insns == d2->u.num_insns)
- return 1;
- else
- return -1;
-
- case DT_mode:
- return d1->u.mode == d2->u.mode;
-
- case DT_code:
- return d1->u.code == d2->u.code;
-
- case DT_veclen:
- return d1->u.veclen == d2->u.veclen;
-
- case DT_elt_zero_int:
- case DT_elt_one_int:
- case DT_elt_zero_wide:
- case DT_elt_zero_wide_safe:
- return d1->u.intval == d2->u.intval;
-
- default:
- break;
- }
- }
-
- /* 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->type == DT_pred || d2->type == DT_pred)
- {
- if (d2->type == DT_pred)
- {
- struct decision_test *tmp;
- tmp = d1, d1 = d2, d2 = tmp;
- }
-
- /* If D2 tests a mode, see if it matches D1. */
- if (d1->u.pred.mode != VOIDmode)
- {
- if (d2->type == DT_mode)
- {
- if (d1->u.pred.mode != d2->u.mode
- /* The mode of an address_operand predicate is the
- mode of the memory, not the operand. It can only
- be used for testing the predicate, so we must
- ignore it here. */
- && strcmp (d1->u.pred.name, "address_operand") != 0)
- return 0;
- }
- /* Don't check two predicate modes here, because if both predicates
- accept CONST_INT, then both can still be true even if the modes
- are different. If they don't accept CONST_INT, there will be a
- separate DT_mode that will make maybe_both_true_1 return 0. */
- }
-
- if (d1->u.pred.data)
- {
- /* If D2 tests a code, see if it is in the list of valid
- codes for D1's predicate. */
- if (d2->type == DT_code)
- {
- if (!d1->u.pred.data->codes[d2->u.code])
- return 0;
- }
-
- /* Otherwise see if the predicates have any codes in common. */
- else if (d2->type == DT_pred && d2->u.pred.data)
- {
- bool common = false;
- enum rtx_code c;
-
- for (c = 0; c < NUM_RTX_CODE; c++)
- if (d1->u.pred.data->codes[c] && d2->u.pred.data->codes[c])
- {
- common = true;
- break;
- }
-
- if (!common)
- return 0;
- }
- }
- }
-
- /* Tests vs veclen may be known when strict equality is involved. */
- if (d1->type == DT_veclen && d2->type == DT_veclen_ge)
- return d1->u.veclen >= d2->u.veclen;
- if (d1->type == DT_veclen_ge && d2->type == DT_veclen)
- return d2->u.veclen >= d1->u.veclen;
-
- return -1;
-}
-
-/* A subroutine of maybe_both_true; examines all the tests for a given node.
- Returns > 0 for "definitely both true" and < 0 for "maybe both true". */
-
-static int
-maybe_both_true_1 (struct decision_test *d1, struct decision_test *d2)
-{
- struct decision_test *t1, *t2;
-
- /* A match_operand with no predicate can match anything. Recognize
- this by the existence of a lone DT_accept_op test. */
- if (d1->type == DT_accept_op || d2->type == DT_accept_op)
- return 1;
-
- /* Eliminate pairs of tests while they can exactly match. */
- while (d1 && d2 && d1->type == d2->type)
- {
- if (maybe_both_true_2 (d1, d2) == 0)
- return 0;
- d1 = d1->next, d2 = d2->next;
- }
-
- /* After that, consider all pairs. */
- for (t1 = d1; t1 ; t1 = t1->next)
- for (t2 = d2; t2 ; t2 = t2->next)
- if (maybe_both_true_2 (t1, t2) == 0)
- return 0;
-
- return -1;
-}
-
-/* Return 0 if we can prove that there is no RTL that can match both
- D1 and D2. Otherwise, return 1 (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 nonzero if we are to only look at the top level and not
- recursively descend. */
-
-static int
-maybe_both_true (struct decision *d1, struct decision *d2,
- int toplevel)
-{
- struct decision *p1, *p2;
- int cmp;
-
- /* Don't compare strings on the different positions in insn. Doing so
- is incorrect and results in false matches from constructs like
-
- [(set (subreg:HI (match_operand:SI "register_operand" "r") 0)
- (subreg:HI (match_operand:SI "register_operand" "r") 0))]
- vs
- [(set (match_operand:HI "register_operand" "r")
- (match_operand:HI "register_operand" "r"))]
-
- If we are presented with such, we are recursing through the remainder
- of a node's success nodes (from the loop at the end of this function).
- Skip forward until we come to a position that matches.
-
- Due to the way position strings are constructed, we know that iterating
- forward from the lexically lower position (e.g. "00") will run into
- the lexically higher position (e.g. "1") and not the other way around.
- This saves a bit of effort. */
-
- cmp = strcmp (d1->position, d2->position);
- if (cmp != 0)
- {
- gcc_assert (!toplevel);
-
- /* If the d2->position was lexically lower, swap. */
- if (cmp > 0)
- p1 = d1, d1 = d2, d2 = p1;
-
- if (d1->success.first == 0)
- return 1;
- for (p1 = d1->success.first; p1; p1 = p1->next)
- if (maybe_both_true (p1, d2, 0))
- return 1;
-
- return 0;
- }
-
- /* Test the current level. */
- cmp = maybe_both_true_1 (d1->tests, d2->tests);
- if (cmp >= 0)
- return cmp;
-
- /* We can't prove that D1 and D2 cannot both be true. If we are only
- to check the top level, return 1. 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 1;
-
- for (p1 = d1->success.first; p1; p1 = p1->next)
- for (p2 = d2->success.first; p2; p2 = p2->next)
- if (maybe_both_true (p1, p2, 0))
- return 1;
-
- return 0;
-}
-
-/* A subroutine of nodes_identical. Examine two tests for equivalence. */
-
-static int
-nodes_identical_1 (struct decision_test *d1, struct decision_test *d2)
-{
- switch (d1->type)
- {
- case DT_num_insns:
- return d1->u.num_insns == d2->u.num_insns;
-
- case DT_mode:
- return d1->u.mode == d2->u.mode;
-
- case DT_code:
- return d1->u.code == d2->u.code;
-
- case DT_pred:
- return (d1->u.pred.mode == d2->u.pred.mode
- && strcmp (d1->u.pred.name, d2->u.pred.name) == 0);
-
- case DT_c_test:
- return strcmp (d1->u.c_test, d2->u.c_test) == 0;
-
- case DT_veclen:
- case DT_veclen_ge:
- return d1->u.veclen == d2->u.veclen;
-
- case DT_dup:
- return d1->u.dup == d2->u.dup;
-
- case DT_elt_zero_int:
- case DT_elt_one_int:
- case DT_elt_zero_wide:
- case DT_elt_zero_wide_safe:
- return d1->u.intval == d2->u.intval;
-
- case DT_accept_op:
- return d1->u.opno == d2->u.opno;
-
- case DT_accept_insn:
- /* Differences will be handled in merge_accept_insn. */
- return 1;
-
- default:
- gcc_unreachable ();
- }
-}
-
-/* True iff the two nodes are identical (on one level only). Due
- to the way these lists are constructed, we shouldn't have to
- consider different orderings on the tests. */
-
-static int
-nodes_identical (struct decision *d1, struct decision *d2)
-{
- struct decision_test *t1, *t2;
-
- for (t1 = d1->tests, t2 = d2->tests; t1 && t2; t1 = t1->next, t2 = t2->next)
- {
- if (t1->type != t2->type)
- return 0;
- if (! nodes_identical_1 (t1, t2))
- return 0;
- }
-
- /* For success, they should now both be null. */
- if (t1 != t2)
- return 0;
-
- /* Check that their subnodes are at the same position, as any one set
- of sibling decisions must be at the same position. Allowing this
- requires complications to find_afterward and when change_state is
- invoked. */
- if (d1->success.first
- && d2->success.first
- && strcmp (d1->success.first->position, d2->success.first->position))
- return 0;
-
- return 1;
-}
-
-/* A subroutine of merge_trees; given two nodes that have been declared
- identical, cope with two insn accept states. If they differ in the
- number of clobbers, then the conflict was created by make_insn_sequence
- and we can drop the with-clobbers version on the floor. If both
- nodes have no additional clobbers, we have found an ambiguity in the
- source machine description. */
-
-static void
-merge_accept_insn (struct decision *oldd, struct decision *addd)
-{
- struct decision_test *old, *add;
-
- for (old = oldd->tests; old; old = old->next)
- if (old->type == DT_accept_insn)
- break;
- if (old == NULL)
- return;
-
- for (add = addd->tests; add; add = add->next)
- if (add->type == DT_accept_insn)
- break;
- if (add == NULL)
- return;
-
- /* 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->u.insn.num_clobbers_to_add == 0
- && add->u.insn.num_clobbers_to_add > 0)
- {
- /* Nothing to do here. */
- }
- else if (old->u.insn.num_clobbers_to_add > 0
- && add->u.insn.num_clobbers_to_add == 0)
- {
- /* In this case, replace OLD with ADD. */
- old->u.insn = add->u.insn;
- }
- else
- {
- message_with_line (add->u.insn.lineno, "`%s' matches `%s'",
- get_insn_name (add->u.insn.code_number),
- get_insn_name (old->u.insn.code_number));
- message_with_line (old->u.insn.lineno, "previous definition of `%s'",
- get_insn_name (old->u.insn.code_number));
- error_count++;
- }
-}
-
-/* Merge two decision trees OLDH and ADDH, modifying OLDH destructively. */
-
-static void
-merge_trees (struct decision_head *oldh, struct decision_head *addh)
-{
- struct decision *next, *add;
-
- if (addh->first == 0)
- return;
- if (oldh->first == 0)
- {
- *oldh = *addh;
- return;
- }
-
- /* Trying to merge bits at different positions isn't possible. */
- gcc_assert (!strcmp (oldh->first->position, addh->first->position));
-
- for (add = addh->first; add ; add = next)
- {
- struct decision *old, *insert_before = NULL;
-
- 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)
- {
- if (nodes_identical (old, add))
- {
- merge_accept_insn (old, add);
- merge_trees (&old->success, &add->success);
- goto merged_nodes;
- }
-
- if (maybe_both_true (old, add, 0))
- break;
-
- /* Insert the nodes in DT test type order, which is roughly
- how expensive/important the test is. Given that the tests
- are also ordered within the list, examining the first is
- sufficient. */
- if ((int) add->tests->type < (int) old->tests->type)
- insert_before = old;
- }
-
- if (insert_before == NULL)
- {
- add->next = NULL;
- add->prev = oldh->last;
- oldh->last->next = add;
- oldh->last = add;
- }
- else
- {
- if ((add->prev = insert_before->prev) != NULL)
- add->prev->next = add;
- else
- oldh->first = add;
- add->next = insert_before;
- insert_before->prev = add;
- }
-
- merged_nodes:;
- }
-}
-
-/* Walk the tree looking for sub-nodes that perform common tests.
- Factor out the common test into a new node. This enables us
- (depending on the test type) to emit switch statements later. */
-
-static void
-factor_tests (struct decision_head *head)
-{
- struct decision *first, *next;
-
- for (first = head->first; first && first->next; first = next)
- {
- enum decision_type type;
- struct decision *new, *old_last;
-
- type = first->tests->type;
- next = first->next;
-
- /* Want at least two compatible sequential nodes. */
- if (next->tests->type != type)
- continue;
-
- /* Don't want all node types, just those we can turn into
- switch statements. */
- if (type != DT_mode
- && type != DT_code
- && type != DT_veclen
- && type != DT_elt_zero_int
- && type != DT_elt_one_int
- && type != DT_elt_zero_wide_safe)
- continue;
-
- /* If we'd been performing more than one test, create a new node
- below our first test. */
- if (first->tests->next != NULL)
- {
- new = new_decision (first->position, &first->success);
- new->tests = first->tests->next;
- first->tests->next = NULL;
- }
-
- /* Crop the node tree off after our first test. */
- first->next = NULL;
- old_last = head->last;
- head->last = first;
-
- /* For each compatible test, adjust to perform only one test in
- the top level node, then merge the node back into the tree. */
- do
- {
- struct decision_head h;
-
- if (next->tests->next != NULL)
- {
- new = new_decision (next->position, &next->success);
- new->tests = next->tests->next;
- next->tests->next = NULL;
- }
- new = next;
- next = next->next;
- new->next = NULL;
- h.first = h.last = new;
-
- merge_trees (head, &h);
- }
- while (next && next->tests->type == type);
-
- /* After we run out of compatible tests, graft the remaining nodes
- back onto the tree. */
- if (next)
- {
- next->prev = head->last;
- head->last->next = next;
- head->last = old_last;
- }
- }
-
- /* Recurse. */
- for (first = head->first; first; first = first->next)
- factor_tests (&first->success);
-}
-
-/* After factoring, try to simplify the tests on any one node.
- Tests that are useful for switch statements are recognizable
- by having only a single test on a node -- we'll be manipulating
- nodes with multiple tests:
-
- If we have mode tests or code tests that are redundant with
- predicates, remove them. */
-
-static void
-simplify_tests (struct decision_head *head)
-{
- struct decision *tree;
-
- for (tree = head->first; tree; tree = tree->next)
- {
- struct decision_test *a, *b;
-
- a = tree->tests;
- b = a->next;
- if (b == NULL)
- continue;
-
- /* Find a predicate node. */
- while (b && b->type != DT_pred)
- b = b->next;
- if (b)
- {
- /* Due to how these tests are constructed, we don't even need
- to check that the mode and code are compatible -- they were
- generated from the predicate in the first place. */
- while (a->type == DT_mode || a->type == DT_code)
- a = a->next;
- tree->tests = a;
- }
- }
-
- /* Recurse. */
- for (tree = head->first; tree; tree = tree->next)
- simplify_tests (&tree->success);
-}
-
-/* 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. */
-
-static int
-break_out_subroutines (struct decision_head *head, int initial)
-{
- int size = 0;
- struct decision *sub;
-
- for (sub = head->first; sub; sub = sub->next)
- size += 1 + break_out_subroutines (&sub->success, 0);
-
- if (size > SUBROUTINE_THRESHOLD && ! initial)
- {
- head->first->subroutine_number = ++next_subroutine_number;
- size = 1;
- }
- return size;
-}
-
-/* For each node p, find the next alternative that might be true
- when p is true. */
-
-static void
-find_afterward (struct decision_head *head, struct decision *real_afterward)
-{
- struct decision *p, *q, *afterward;
-
- /* We can't propagate alternatives across subroutine boundaries.
- This is not incorrect, merely a minor optimization loss. */
-
- p = head->first;
- afterward = (p->subroutine_number > 0 ? NULL : real_afterward);
-
- for ( ; p ; p = p->next)
- {
- /* Find the next node that might be true if this one fails. */
- for (q = p->next; q ; q = q->next)
- if (maybe_both_true (p, q, 1))
- break;
-
- /* If we reached the end of the list without finding one,
- use the incoming afterward position. */
- if (!q)
- q = afterward;
- p->afterward = q;
- if (q)
- q->need_label = 1;
- }
-
- /* Recurse. */
- for (p = head->first; p ; p = p->next)
- if (p->success.first)
- find_afterward (&p->success, p->afterward);
-
- /* When we are generating a subroutine, record the real afterward
- position in the first node where write_tree can find it, and we
- can do the right thing at the subroutine call site. */
- p = head->first;
- if (p->subroutine_number > 0)
- p->afterward = real_afterward;
-}
-
-/* Assuming that the state of argument is denoted by OLDPOS, take whatever
- actions are necessary to move to NEWPOS. If we fail to move to the
- new state, branch to node AFTERWARD if nonzero, otherwise return.
-
- Failure to move to the new state can only occur if we are trying to
- match multiple insns and we try to step past the end of the stream. */
-
-static void
-change_state (const char *oldpos, const char *newpos, const char *indent)
-{
- int odepth = strlen (oldpos);
- int ndepth = strlen (newpos);
- int depth;
- int old_has_insn, new_has_insn;
-
- /* Pop up as many levels as necessary. */
- for (depth = odepth; strncmp (oldpos, newpos, depth) != 0; --depth)
- continue;
-
- /* Hunt for the last [A-Z] in both strings. */
- for (old_has_insn = odepth - 1; old_has_insn >= 0; --old_has_insn)
- if (ISUPPER (oldpos[old_has_insn]))
- break;
- for (new_has_insn = ndepth - 1; new_has_insn >= 0; --new_has_insn)
- if (ISUPPER (newpos[new_has_insn]))
- break;
-
- /* Go down to desired level. */
- while (depth < ndepth)
- {
- /* It's a different insn from the first one. */
- if (ISUPPER (newpos[depth]))
- {
- printf ("%stem = peep2_next_insn (%d);\n",
- indent, newpos[depth] - 'A');
- printf ("%sx%d = PATTERN (tem);\n", indent, depth + 1);
- }
- else if (ISLOWER (newpos[depth]))
- printf ("%sx%d = XVECEXP (x%d, 0, %d);\n",
- indent, depth + 1, depth, newpos[depth] - 'a');
- else
- printf ("%sx%d = XEXP (x%d, %c);\n",
- indent, depth + 1, depth, newpos[depth]);
- ++depth;
- }
-}
-
-/* Print the enumerator constant for CODE -- the upcase version of
- the name. */
-
-static void
-print_code (enum rtx_code code)
-{
- const char *p;
- for (p = GET_RTX_NAME (code); *p; p++)
- putchar (TOUPPER (*p));
-}
-
-/* Emit code to cross an afterward link -- change state and branch. */
-
-static void
-write_afterward (struct decision *start, struct decision *afterward,
- const char *indent)
-{
- if (!afterward || start->subroutine_number > 0)
- printf("%sgoto ret0;\n", indent);
- else
- {
- change_state (start->position, afterward->position, indent);
- printf ("%sgoto L%d;\n", indent, afterward->number);
- }
-}
-
-/* Emit a HOST_WIDE_INT as an integer constant expression. We need to take
- special care to avoid "decimal constant is so large that it is unsigned"
- warnings in the resulting code. */
-
-static void
-print_host_wide_int (HOST_WIDE_INT val)
-{
- HOST_WIDE_INT min = (unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1);
- if (val == min)
- printf ("(" HOST_WIDE_INT_PRINT_DEC_C "-1)", val + 1);
- else
- printf (HOST_WIDE_INT_PRINT_DEC_C, val);
-}
-
-/* Emit a switch statement, if possible, for an initial sequence of
- nodes at START. Return the first node yet untested. */
-
-static struct decision *
-write_switch (struct decision *start, int depth)
-{
- struct decision *p = start;
- enum decision_type type = p->tests->type;
- struct decision *needs_label = NULL;
-
- /* If we have two or more nodes in sequence that test the same one
- thing, we may be able to use a switch statement. */
-
- if (!p->next
- || p->tests->next
- || p->next->tests->type != type
- || p->next->tests->next
- || nodes_identical_1 (p->tests, p->next->tests))
- return p;
-
- /* DT_code is special in that we can do interesting things with
- known predicates at the same time. */
- if (type == DT_code)
- {
- char codemap[NUM_RTX_CODE];
- struct decision *ret;
- RTX_CODE code;
-
- memset (codemap, 0, sizeof(codemap));
-
- printf (" switch (GET_CODE (x%d))\n {\n", depth);
- code = p->tests->u.code;
- do
- {
- if (p != start && p->need_label && needs_label == NULL)
- needs_label = p;
-
- printf (" case ");
- print_code (code);
- printf (":\n goto L%d;\n", p->success.first->number);
- p->success.first->need_label = 1;
-
- codemap[code] = 1;
- p = p->next;
- }
- while (p
- && ! p->tests->next
- && p->tests->type == DT_code
- && ! codemap[code = p->tests->u.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 predicates called. */
-
- /* Note that while we write out cases for these predicates here,
- we don't actually write the test here, as it gets kinda messy.
- It is trivial to leave this to later by telling our caller that
- we only processed the CODE tests. */
- if (needs_label != NULL)
- ret = needs_label;
- else
- ret = p;
-
- while (p && p->tests->type == DT_pred && p->tests->u.pred.data)
- {
- const struct pred_data *data = p->tests->u.pred.data;
- RTX_CODE c;
- for (c = 0; c < NUM_RTX_CODE; c++)
- if (codemap[c] && data->codes[c])
- goto pred_done;
-
- for (c = 0; c < NUM_RTX_CODE; c++)
- if (data->codes[c])
- {
- fputs (" case ", stdout);
- print_code (c);
- fputs (":\n", stdout);
- codemap[c] = 1;
- }
-
- printf (" goto L%d;\n", p->number);
- p->need_label = 1;
- p = p->next;
- }
-
- pred_done:
- /* Make the default case skip the predicates we managed to match. */
-
- printf (" default:\n");
- if (p != ret)
- {
- if (p)
- {
- printf (" goto L%d;\n", p->number);
- p->need_label = 1;
- }
- else
- write_afterward (start, start->afterward, " ");
- }
- else
- printf (" break;\n");
- printf (" }\n");
-
- return ret;
- }
- else if (type == DT_mode
- || type == DT_veclen
- || type == DT_elt_zero_int
- || type == DT_elt_one_int
- || type == DT_elt_zero_wide_safe)
- {
- const char *indent = "";
-
- /* We cast switch parameter to integer, so we must ensure that the value
- fits. */
- if (type == DT_elt_zero_wide_safe)
- {
- indent = " ";
- printf(" if ((int) XWINT (x%d, 0) == XWINT (x%d, 0))\n", depth, depth);
- }
- printf ("%s switch (", indent);
- switch (type)
- {
- case DT_mode:
- printf ("GET_MODE (x%d)", depth);
- break;
- case DT_veclen:
- printf ("XVECLEN (x%d, 0)", depth);
- break;
- case DT_elt_zero_int:
- printf ("XINT (x%d, 0)", depth);
- break;
- case DT_elt_one_int:
- printf ("XINT (x%d, 1)", depth);
- break;
- case DT_elt_zero_wide_safe:
- /* Convert result of XWINT to int for portability since some C
- compilers won't do it and some will. */
- printf ("(int) XWINT (x%d, 0)", depth);
- break;
- default:
- gcc_unreachable ();
- }
- printf (")\n%s {\n", indent);
-
- do
- {
- /* Merge trees will not unify identical nodes if their
- sub-nodes are at different levels. Thus we must check
- for duplicate cases. */
- struct decision *q;
- for (q = start; q != p; q = q->next)
- if (nodes_identical_1 (p->tests, q->tests))
- goto case_done;
-
- if (p != start && p->need_label && needs_label == NULL)
- needs_label = p;
-
- printf ("%s case ", indent);
- switch (type)
- {
- case DT_mode:
- printf ("%smode", GET_MODE_NAME (p->tests->u.mode));
- break;
- case DT_veclen:
- printf ("%d", p->tests->u.veclen);
- break;
- case DT_elt_zero_int:
- case DT_elt_one_int:
- case DT_elt_zero_wide:
- case DT_elt_zero_wide_safe:
- print_host_wide_int (p->tests->u.intval);
- break;
- default:
- gcc_unreachable ();
- }
- printf (":\n%s goto L%d;\n", indent, p->success.first->number);
- p->success.first->need_label = 1;
-
- p = p->next;
- }
- while (p && p->tests->type == type && !p->tests->next);
-
- case_done:
- printf ("%s default:\n%s break;\n%s }\n",
- indent, indent, indent);
-
- return needs_label != NULL ? needs_label : p;
- }
- else
- {
- /* None of the other tests are amenable. */
- return p;
- }
-}
-
-/* Emit code for one test. */
-
-static void
-write_cond (struct decision_test *p, int depth,
- enum routine_type subroutine_type)
-{
- switch (p->type)
- {
- case DT_num_insns:
- printf ("peep2_current_count >= %d", p->u.num_insns);
- break;
-
- case DT_mode:
- printf ("GET_MODE (x%d) == %smode", depth, GET_MODE_NAME (p->u.mode));
- break;
-
- case DT_code:
- printf ("GET_CODE (x%d) == ", depth);
- print_code (p->u.code);
- break;
-
- case DT_veclen:
- printf ("XVECLEN (x%d, 0) == %d", depth, p->u.veclen);
- break;
-
- case DT_elt_zero_int:
- printf ("XINT (x%d, 0) == %d", depth, (int) p->u.intval);
- break;
-
- case DT_elt_one_int:
- printf ("XINT (x%d, 1) == %d", depth, (int) p->u.intval);
- break;
-
- case DT_elt_zero_wide:
- case DT_elt_zero_wide_safe:
- printf ("XWINT (x%d, 0) == ", depth);
- print_host_wide_int (p->u.intval);
- break;
-
- case DT_const_int:
- printf ("x%d == const_int_rtx[MAX_SAVED_CONST_INT + (%d)]",
- depth, (int) p->u.intval);
- break;
-
- case DT_veclen_ge:
- printf ("XVECLEN (x%d, 0) >= %d", depth, p->u.veclen);
- break;
-
- case DT_dup:
- printf ("rtx_equal_p (x%d, operands[%d])", depth, p->u.dup);
- break;
-
- case DT_pred:
- printf ("%s (x%d, %smode)", p->u.pred.name, depth,
- GET_MODE_NAME (p->u.pred.mode));
- break;
-
- case DT_c_test:
- print_c_condition (p->u.c_test);
- break;
-
- case DT_accept_insn:
- gcc_assert (subroutine_type == RECOG);
- gcc_assert (p->u.insn.num_clobbers_to_add);
- printf ("pnum_clobbers != NULL");
- break;
-
- default:
- gcc_unreachable ();
- }
-}
-
-/* Emit code for one action. The previous tests have succeeded;
- TEST is the last of the chain. In the normal case we simply
- perform a state change. For the `accept' tests we must do more work. */
-
-static void
-write_action (struct decision *p, struct decision_test *test,
- int depth, int uncond, struct decision *success,
- enum routine_type subroutine_type)
-{
- const char *indent;
- int want_close = 0;
-
- if (uncond)
- indent = " ";
- else if (test->type == DT_accept_op || test->type == DT_accept_insn)
- {
- fputs (" {\n", stdout);
- indent = " ";
- want_close = 1;
- }
- else
- indent = " ";
-
- if (test->type == DT_accept_op)
- {
- printf("%soperands[%d] = x%d;\n", indent, test->u.opno, depth);
-
- /* Only allow DT_accept_insn to follow. */
- if (test->next)
- {
- test = test->next;
- gcc_assert (test->type == DT_accept_insn);
- }
- }
-
- /* Sanity check that we're now at the end of the list of tests. */
- gcc_assert (!test->next);
-
- if (test->type == DT_accept_insn)
- {
- switch (subroutine_type)
- {
- case RECOG:
- if (test->u.insn.num_clobbers_to_add != 0)
- printf ("%s*pnum_clobbers = %d;\n",
- indent, test->u.insn.num_clobbers_to_add);
- printf ("%sreturn %d; /* %s */\n", indent,
- test->u.insn.code_number,
- get_insn_name (test->u.insn.code_number));
- break;
-
- case SPLIT:
- printf ("%sreturn gen_split_%d (insn, operands);\n",
- indent, test->u.insn.code_number);
- break;
-
- case PEEPHOLE2:
- {
- int match_len = 0, i;
-
- for (i = strlen (p->position) - 1; i >= 0; --i)
- if (ISUPPER (p->position[i]))
- {
- match_len = p->position[i] - 'A';
- break;
- }
- printf ("%s*_pmatch_len = %d;\n", indent, match_len);
- printf ("%stem = gen_peephole2_%d (insn, operands);\n",
- indent, test->u.insn.code_number);
- printf ("%sif (tem != 0)\n%s return tem;\n", indent, indent);
- }
- break;
-
- default:
- gcc_unreachable ();
- }
- }
- else
- {
- printf("%sgoto L%d;\n", indent, success->number);
- success->need_label = 1;
- }
-
- if (want_close)
- fputs (" }\n", stdout);
-}
-
-/* Return 1 if the test is always true and has no fallthru path. Return -1
- if the test does have a fallthru path, but requires that the condition be
- terminated. Otherwise return 0 for a normal test. */
-/* ??? is_unconditional is a stupid name for a tri-state function. */
-
-static int
-is_unconditional (struct decision_test *t, enum routine_type subroutine_type)
-{
- if (t->type == DT_accept_op)
- return 1;
-
- if (t->type == DT_accept_insn)
- {
- switch (subroutine_type)
- {
- case RECOG:
- return (t->u.insn.num_clobbers_to_add == 0);
- case SPLIT:
- return 1;
- case PEEPHOLE2:
- return -1;
- default:
- gcc_unreachable ();
- }
- }
-
- return 0;
-}
-
-/* Emit code for one node -- the conditional and the accompanying action.
- Return true if there is no fallthru path. */
-
-static int
-write_node (struct decision *p, int depth,
- enum routine_type subroutine_type)
-{
- struct decision_test *test, *last_test;
- int uncond;
-
- /* Scan the tests and simplify comparisons against small
- constants. */
- for (test = p->tests; test; test = test->next)
- {
- if (test->type == DT_code
- && test->u.code == CONST_INT
- && test->next
- && test->next->type == DT_elt_zero_wide_safe
- && -MAX_SAVED_CONST_INT <= test->next->u.intval
- && test->next->u.intval <= MAX_SAVED_CONST_INT)
- {
- test->type = DT_const_int;
- test->u.intval = test->next->u.intval;
- test->next = test->next->next;
- }
- }
-
- last_test = test = p->tests;
- uncond = is_unconditional (test, subroutine_type);
- if (uncond == 0)
- {
- printf (" if (");
- write_cond (test, depth, subroutine_type);
-
- while ((test = test->next) != NULL)
- {
- last_test = test;
- if (is_unconditional (test, subroutine_type))
- break;
-
- printf ("\n && ");
- write_cond (test, depth, subroutine_type);
- }
-
- printf (")\n");
- }
-
- write_action (p, last_test, depth, uncond, p->success.first, subroutine_type);
-
- return uncond > 0;
-}
-
-/* Emit code for all of the sibling nodes of HEAD. */
-
-static void
-write_tree_1 (struct decision_head *head, int depth,
- enum routine_type subroutine_type)
-{
- struct decision *p, *next;
- int uncond = 0;
-
- for (p = head->first; p ; p = next)
- {
- /* The label for the first element was printed in write_tree. */
- if (p != head->first && p->need_label)
- OUTPUT_LABEL (" ", p->number);
-
- /* Attempt to write a switch statement for a whole sequence. */
- next = write_switch (p, depth);
- if (p != next)
- uncond = 0;
- else
- {
- /* Failed -- fall back and write one node. */
- uncond = write_node (p, depth, subroutine_type);
- next = p->next;
- }
- }
-
- /* Finished with this chain. Close a fallthru path by branching
- to the afterward node. */
- if (! uncond)
- write_afterward (head->last, head->last->afterward, " ");
-}
-
-/* Write out the decision tree starting at HEAD. PREVPOS is the
- position at the node that branched to this node. */
-
-static void
-write_tree (struct decision_head *head, const char *prevpos,
- enum routine_type type, int initial)
-{
- struct decision *p = head->first;
-
- putchar ('\n');
- if (p->need_label)
- OUTPUT_LABEL (" ", p->number);
-
- if (! initial && p->subroutine_number > 0)
- {
- static const char * const name_prefix[] = {
- "recog", "split", "peephole2"
- };
-
- static const char * const call_suffix[] = {
- ", pnum_clobbers", "", ", _pmatch_len"
- };
-
- /* This node has been broken out into a separate subroutine.
- Call it, test the result, and branch accordingly. */
-
- if (p->afterward)
- {
- printf (" tem = %s_%d (x0, insn%s);\n",
- name_prefix[type], p->subroutine_number, call_suffix[type]);
- if (IS_SPLIT (type))
- printf (" if (tem != 0)\n return tem;\n");
- else
- printf (" if (tem >= 0)\n return tem;\n");
-
- change_state (p->position, p->afterward->position, " ");
- printf (" goto L%d;\n", p->afterward->number);
- }
- else
- {
- printf (" return %s_%d (x0, insn%s);\n",
- name_prefix[type], p->subroutine_number, call_suffix[type]);
- }
- }
- else
- {
- int depth = strlen (p->position);
-
- change_state (prevpos, p->position, " ");
- write_tree_1 (head, depth, type);
-
- for (p = head->first; p; p = p->next)
- if (p->success.first)
- write_tree (&p->success, p->position, type, 0);
- }
-}
-
-/* Write out a subroutine of type TYPE to do comparisons starting at
- node TREE. */
-
-static void
-write_subroutine (struct decision_head *head, enum routine_type type)
-{
- int subfunction = head->first ? head->first->subroutine_number : 0;
- const char *s_or_e;
- char extension[32];
- int i;
-
- s_or_e = subfunction ? "static " : "";
-
- if (subfunction)
- sprintf (extension, "_%d", subfunction);
- else if (type == RECOG)
- extension[0] = '\0';
- else
- strcpy (extension, "_insns");
-
- switch (type)
- {
- case RECOG:
- printf ("%sint\n\
-recog%s (rtx x0 ATTRIBUTE_UNUSED,\n\trtx insn ATTRIBUTE_UNUSED,\n\tint *pnum_clobbers ATTRIBUTE_UNUSED)\n", s_or_e, extension);
- break;
- case SPLIT:
- printf ("%srtx\n\
-split%s (rtx x0 ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED)\n",
- s_or_e, extension);
- break;
- case PEEPHOLE2:
- printf ("%srtx\n\
-peephole2%s (rtx x0 ATTRIBUTE_UNUSED,\n\trtx insn ATTRIBUTE_UNUSED,\n\tint *_pmatch_len ATTRIBUTE_UNUSED)\n",
- s_or_e, extension);
- break;
- }
-
- printf ("{\n rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];\n");
- for (i = 1; i <= max_depth; i++)
- printf (" rtx x%d ATTRIBUTE_UNUSED;\n", i);
-
- printf (" %s tem ATTRIBUTE_UNUSED;\n", IS_SPLIT (type) ? "rtx" : "int");
-
- if (!subfunction)
- printf (" recog_data.insn = NULL_RTX;\n");
-
- if (head->first)
- write_tree (head, "", type, 1);
- else
- printf (" goto ret0;\n");
-
- printf (" ret0:\n return %d;\n}\n\n", IS_SPLIT (type) ? 0 : -1);
-}
-
-/* In break_out_subroutines, we discovered the boundaries for the
- subroutines, but did not write them out. Do so now. */
-
-static void
-write_subroutines (struct decision_head *head, enum routine_type type)
-{
- struct decision *p;
-
- for (p = head->first; p ; p = p->next)
- if (p->success.first)
- write_subroutines (&p->success, type);
-
- if (head->first->subroutine_number > 0)
- write_subroutine (head, type);
-}
-
-/* Begin the output file. */
-
-static void
-write_header (void)
-{
- puts ("\
-/* Generated automatically by the program `genrecog' from the target\n\
- machine description file. */\n\
-\n\
-#include \"config.h\"\n\
-#include \"system.h\"\n\
-#include \"coretypes.h\"\n\
-#include \"tm.h\"\n\
-#include \"rtl.h\"\n\
-#include \"tm_p.h\"\n\
-#include \"function.h\"\n\
-#include \"insn-config.h\"\n\
-#include \"recog.h\"\n\
-#include \"real.h\"\n\
-#include \"output.h\"\n\
-#include \"flags.h\"\n\
-#include \"hard-reg-set.h\"\n\
-#include \"resource.h\"\n\
-#include \"toplev.h\"\n\
-#include \"reload.h\"\n\
-#include \"tm-constrs.h\"\n\
-\n");
-
- puts ("\n\
-/* `recog' contains a decision tree that recognizes whether the rtx\n\
- X0 is a valid instruction.\n\
-\n\
- recog returns -1 if the rtx is not valid. If the rtx is valid, recog\n\
- returns a nonnegative number which is the insn code number for the\n\
- pattern that matched. This is the same as the order in the machine\n\
- description of the entry that matched. This number can be used as an\n\
- index into `insn_data' and other tables.\n");
- puts ("\
- The third argument to recog is an optional pointer to an int. If\n\
- present, recog will accept a pattern if it matches except for missing\n\
- CLOBBER expressions at the end. In that case, the value pointed to by\n\
- the optional pointer will be set to the number of CLOBBERs that need\n\
- to be added (it should be initialized to zero by the caller). If it");
- puts ("\
- is set nonzero, the caller should allocate a PARALLEL of the\n\
- appropriate size, copy the initial entries, and call add_clobbers\n\
- (found in insn-emit.c) to fill in the CLOBBERs.\n\
-");
-
- puts ("\n\
- The function split_insns returns 0 if the rtl could not\n\
- be split or the split rtl as an INSN list if it can be.\n\
-\n\
- The function peephole2_insns returns 0 if the rtl could not\n\
- be matched. If there was a match, the new rtl is returned in an INSN list,\n\
- and LAST_INSN will point to the last recognized insn in the old sequence.\n\
-*/\n\n");
-}
-
-
-/* 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 (rtx insn, enum routine_type type)
-{
- 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;
- struct decision_head clobber_head;
-
- /* Build a similar insn without the clobbers. */
- 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);
- }
-
- /* Recognize it. */
- memset (&clobber_head, 0, sizeof(clobber_head));
- last = add_to_sequence (new, &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);
-}
-
-extern int main (int, char **);
-
-int
-main (int argc, char **argv)
-{
- rtx desc;
- struct decision_head recog_tree, split_tree, peephole2_tree, h;
-
- progname = "genrecog";
-
- memset (&recog_tree, 0, sizeof recog_tree);
- memset (&split_tree, 0, sizeof split_tree);
- memset (&peephole2_tree, 0, sizeof peephole2_tree);
-
- if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
- return (FATAL_EXIT_CODE);
-
- next_insn_code = 0;
-
- write_header ();
-
- /* Read the machine description. */
-
- while (1)
- {
- desc = read_md_rtx (&pattern_lineno, &next_insn_code);
- if (desc == NULL)
- break;
-
- switch (GET_CODE (desc))
- {
- case DEFINE_PREDICATE:
- case DEFINE_SPECIAL_PREDICATE:
- process_define_predicate (desc);
- break;
-
- case DEFINE_INSN:
- h = make_insn_sequence (desc, RECOG);
- merge_trees (&recog_tree, &h);
- break;
-
- case DEFINE_SPLIT:
- h = make_insn_sequence (desc, SPLIT);
- merge_trees (&split_tree, &h);
- break;
-
- case DEFINE_PEEPHOLE2:
- h = make_insn_sequence (desc, PEEPHOLE2);
- merge_trees (&peephole2_tree, &h);
-
- default:
- /* do nothing */;
- }
- }
-
- if (error_count || have_error)
- return FATAL_EXIT_CODE;
-
- puts ("\n\n");
-
- process_tree (&recog_tree, RECOG);
- process_tree (&split_tree, SPLIT);
- process_tree (&peephole2_tree, PEEPHOLE2);
-
- fflush (stdout);
- return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
-}
-
-static void
-debug_decision_2 (struct decision_test *test)
-{
- switch (test->type)
- {
- case DT_num_insns:
- fprintf (stderr, "num_insns=%d", test->u.num_insns);
- break;
- case DT_mode:
- fprintf (stderr, "mode=%s", GET_MODE_NAME (test->u.mode));
- break;
- case DT_code:
- fprintf (stderr, "code=%s", GET_RTX_NAME (test->u.code));
- break;
- case DT_veclen:
- fprintf (stderr, "veclen=%d", test->u.veclen);
- break;
- case DT_elt_zero_int:
- fprintf (stderr, "elt0_i=%d", (int) test->u.intval);
- break;
- case DT_elt_one_int:
- fprintf (stderr, "elt1_i=%d", (int) test->u.intval);
- break;
- case DT_elt_zero_wide:
- fprintf (stderr, "elt0_w=" HOST_WIDE_INT_PRINT_DEC, test->u.intval);
- break;
- case DT_elt_zero_wide_safe:
- fprintf (stderr, "elt0_ws=" HOST_WIDE_INT_PRINT_DEC, test->u.intval);
- break;
- case DT_veclen_ge:
- fprintf (stderr, "veclen>=%d", test->u.veclen);
- break;
- case DT_dup:
- fprintf (stderr, "dup=%d", test->u.dup);
- break;
- case DT_pred:
- fprintf (stderr, "pred=(%s,%s)",
- test->u.pred.name, GET_MODE_NAME(test->u.pred.mode));
- break;
- case DT_c_test:
- {
- char sub[16+4];
- strncpy (sub, test->u.c_test, sizeof(sub));
- memcpy (sub+16, "...", 4);
- fprintf (stderr, "c_test=\"%s\"", sub);
- }
- break;
- case DT_accept_op:
- fprintf (stderr, "A_op=%d", test->u.opno);
- break;
- case DT_accept_insn:
- fprintf (stderr, "A_insn=(%d,%d)",
- test->u.insn.code_number, test->u.insn.num_clobbers_to_add);
- break;
-
- default:
- gcc_unreachable ();
- }
-}
-
-static void
-debug_decision_1 (struct decision *d, int indent)
-{
- int i;
- struct decision_test *test;
-
- if (d == NULL)
- {
- for (i = 0; i < indent; ++i)
- putc (' ', stderr);
- fputs ("(nil)\n", stderr);
- return;
- }
-
- for (i = 0; i < indent; ++i)
- putc (' ', stderr);
-
- putc ('{', stderr);
- test = d->tests;
- if (test)
- {
- debug_decision_2 (test);
- while ((test = test->next) != NULL)
- {
- fputs (" + ", stderr);
- debug_decision_2 (test);
- }
- }
- fprintf (stderr, "} %d n %d a %d\n", d->number,
- (d->next ? d->next->number : -1),
- (d->afterward ? d->afterward->number : -1));
-}
-
-static void
-debug_decision_0 (struct decision *d, int indent, int maxdepth)
-{
- struct decision *n;
- int i;
-
- if (maxdepth < 0)
- return;
- if (d == NULL)
- {
- for (i = 0; i < indent; ++i)
- putc (' ', stderr);
- fputs ("(nil)\n", stderr);
- return;
- }
-
- debug_decision_1 (d, indent);
- for (n = d->success.first; n ; n = n->next)
- debug_decision_0 (n, indent + 2, maxdepth - 1);
-}
-
-void
-debug_decision (struct decision *d)
-{
- debug_decision_0 (d, 0, 1000000);
-}
-
-void
-debug_decision_list (struct decision *d)
-{
- while (d)
- {
- debug_decision_0 (d, 0, 0);
- d = d->next;
- }
-}