X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fgenrecog.c;h=097faefe8c25cb17452e4eb4a160e6dc67d59b83;hb=f0ed0e8a52bc2aada0e3f4b71c157aa6442cc43c;hp=228a5701eb472955e19b6d9207122d7df468993a;hpb=3164740afa7beae437addc59a72f62dcc159593c;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/genrecog.c b/gcc/genrecog.c index 228a5701eb4..097faefe8c2 100644 --- a/gcc/genrecog.c +++ b/gcc/genrecog.c @@ -1,23 +1,23 @@ /* Generate code from machine description to recognize rtl as insns. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1997, 1998, - 1999, 2000 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. - This file is part of GNU CC. + This file is part of GCC. - GNU CC is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by + 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. - GNU CC is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + 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 GNU CC; see the file COPYING. If not, write to - the Free Software Foundation, 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + along with GCC; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ /* This program is used to produce insn-recog.c, which contains a @@ -43,20 +43,21 @@ This program also generates the function `split_insns', which returns 0 if the rtl could not be split, or it returns the split - rtl in a SEQUENCE. + 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 a SEQUENCE, and LAST_INSN will point + the new rtl is returned in an INSN list, and LAST_INSN will point to the last recognized insn in the old sequence. */ -#include "hconfig.h" +#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)) @@ -65,7 +66,7 @@ static char **insn_name_ptr = 0; static int insn_name_ptr_size = 0; /* A listhead of decision trees. The alternatives to a node are kept - in a doublely-linked list so we can easily add nodes to the proper + in a doubly-linked list so we can easily add nodes to the proper place when merging. */ struct decision_head @@ -73,7 +74,7 @@ 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. */ @@ -88,7 +89,8 @@ struct decision_test { DT_mode, DT_code, DT_veclen, DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide, DT_elt_zero_wide_safe, - DT_veclen_ge, DT_dup, DT_pred, DT_c_test, + DT_const_int, + DT_veclen_ge, DT_dup, DT_pred, DT_c_test, DT_accept_op, DT_accept_insn } type; @@ -100,7 +102,8 @@ struct decision_test struct { const char *name; /* Predicate to call. */ - int index; /* Index into `preds' or -1. */ + const struct pred_data *data; + /* Optimization hints for this predicate. */ enum machine_mode mode; /* Machine mode for node. */ } pred; @@ -159,11 +162,6 @@ static int next_number; static int next_insn_code; -/* Similar, but counts all expressions in the MD file; used for - error messages. */ - -static int next_index; - /* Record the highest depth we ever have so we know how many variables to allocate in each subroutine we make. */ @@ -175,152 +173,305 @@ static int pattern_lineno; /* Count of errors. */ static int error_count; -/* This table contains a list of the rtl codes that can possibly match a - predicate defined in recog.c. 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. */ +/* 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)) + +/* 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 (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. */ + 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; + + 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; + break; + } + } + } + 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 -static struct pred_table +/* 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) { - const char *name; - RTX_CODE codes[NUM_RTX_CODE]; -} preds[] = { - {"general_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF, SUBREG, REG, MEM}}, -#ifdef PREDICATE_CODES - PREDICATE_CODES -#endif - {"address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF, SUBREG, REG, MEM, PLUS, MINUS, MULT}}, - {"register_operand", {SUBREG, REG}}, - {"pmode_register_operand", {SUBREG, REG}}, - {"scratch_operand", {SCRATCH, REG}}, - {"immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF}}, - {"const_int_operand", {CONST_INT}}, - {"const_double_operand", {CONST_INT, CONST_DOUBLE}}, - {"nonimmediate_operand", {SUBREG, REG, MEM}}, - {"nonmemory_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF, SUBREG, REG}}, - {"push_operand", {MEM}}, - {"pop_operand", {MEM}}, - {"memory_operand", {SUBREG, MEM}}, - {"indirect_operand", {SUBREG, MEM}}, - {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU, - UNORDERED, ORDERED, UNEQ, UNGE, UNGT, UNLE, - UNLT, LTGT}}, - {"mode_independent_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF, SUBREG, REG, MEM}} -}; + struct pred_data *pred = xcalloc (sizeof (struct pred_data), 1); + char codes[NUM_RTX_CODE]; + bool seen_one = false; + int i; -#define NUM_KNOWN_PREDS ARRAY_SIZE (preds) + pred->name = XSTR (desc, 0); + if (GET_CODE (desc) == DEFINE_SPECIAL_PREDICATE) + pred->special = 1; -static const char * special_mode_pred_table[] = { -#ifdef SPECIAL_MODE_PREDICATES - SPECIAL_MODE_PREDICATES -#endif - "pmode_register_operand" -}; + compute_predicate_codes (XEXP (desc, 1), codes); -#define NUM_SPECIAL_MODE_PREDS ARRAY_SIZE (special_mode_pred_table) + 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 - PARAMS ((const char *, struct decision_head *)); + (const char *, struct decision_head *); static struct decision_test *new_decision_test - PARAMS ((enum decision_type, struct decision_test ***)); + (enum decision_type, struct decision_test ***); static rtx find_operand - PARAMS ((rtx, int)); + (rtx, int, rtx); static rtx find_matching_operand - PARAMS ((rtx, int)); + (rtx, int); static void validate_pattern - PARAMS ((rtx, rtx, rtx, int)); + (rtx, rtx, rtx, int); static struct decision *add_to_sequence - PARAMS ((rtx, struct decision_head *, const char *, enum routine_type, int)); + (rtx, struct decision_head *, const char *, enum routine_type, int); static int maybe_both_true_2 - PARAMS ((struct decision_test *, struct decision_test *)); + (struct decision_test *, struct decision_test *); static int maybe_both_true_1 - PARAMS ((struct decision_test *, struct decision_test *)); + (struct decision_test *, struct decision_test *); static int maybe_both_true - PARAMS ((struct decision *, struct decision *, int)); + (struct decision *, struct decision *, int); static int nodes_identical_1 - PARAMS ((struct decision_test *, struct decision_test *)); + (struct decision_test *, struct decision_test *); static int nodes_identical - PARAMS ((struct decision *, struct decision *)); + (struct decision *, struct decision *); static void merge_accept_insn - PARAMS ((struct decision *, struct decision *)); + (struct decision *, struct decision *); static void merge_trees - PARAMS ((struct decision_head *, struct decision_head *)); + (struct decision_head *, struct decision_head *); static void factor_tests - PARAMS ((struct decision_head *)); + (struct decision_head *); static void simplify_tests - PARAMS ((struct decision_head *)); + (struct decision_head *); static int break_out_subroutines - PARAMS ((struct decision_head *, int)); + (struct decision_head *, int); static void find_afterward - PARAMS ((struct decision_head *, struct decision *)); + (struct decision_head *, struct decision *); static void change_state - PARAMS ((const char *, const char *, struct decision *, const char *)); + (const char *, const char *, struct decision *, const char *); static void print_code - PARAMS ((enum rtx_code)); + (enum rtx_code); static void write_afterward - PARAMS ((struct decision *, struct decision *, const char *)); + (struct decision *, struct decision *, const char *); static struct decision *write_switch - PARAMS ((struct decision *, int)); + (struct decision *, int); static void write_cond - PARAMS ((struct decision_test *, int, enum routine_type)); + (struct decision_test *, int, enum routine_type); static void write_action - PARAMS ((struct decision *, struct decision_test *, int, int, - struct decision *, enum routine_type)); + (struct decision *, struct decision_test *, int, int, + struct decision *, enum routine_type); static int is_unconditional - PARAMS ((struct decision_test *, enum routine_type)); + (struct decision_test *, enum routine_type); static int write_node - PARAMS ((struct decision *, int, enum routine_type)); + (struct decision *, int, enum routine_type); static void write_tree_1 - PARAMS ((struct decision_head *, int, enum routine_type)); + (struct decision_head *, int, enum routine_type); static void write_tree - PARAMS ((struct decision_head *, const char *, enum routine_type, int)); + (struct decision_head *, const char *, enum routine_type, int); static void write_subroutine - PARAMS ((struct decision_head *, enum routine_type)); + (struct decision_head *, enum routine_type); static void write_subroutines - PARAMS ((struct decision_head *, enum routine_type)); + (struct decision_head *, enum routine_type); static void write_header - PARAMS ((void)); + (void); static struct decision_head make_insn_sequence - PARAMS ((rtx, enum routine_type)); + (rtx, enum routine_type); static void process_tree - PARAMS ((struct decision_head *, enum routine_type)); - + (struct decision_head *, enum routine_type); + static void record_insn_name - PARAMS ((int, const char *)); + (int, const char *); static void debug_decision_0 - PARAMS ((struct decision *, int, int)); + (struct decision *, int, int); static void debug_decision_1 - PARAMS ((struct decision *, int)); + (struct decision *, int); static void debug_decision_2 - PARAMS ((struct decision_test *)); + (struct decision_test *); extern void debug_decision - PARAMS ((struct decision *)); + (struct decision *); extern void debug_decision_list - PARAMS ((struct decision *)); + (struct decision *); /* Create a new node in sequence after LAST. */ static struct decision * -new_decision (position, last) - const char *position; - struct decision_head *last; +new_decision (const char *position, struct decision_head *last) { - register struct decision *new - = (struct decision *) xmalloc (sizeof (struct decision)); + struct decision *new = xcalloc (1, sizeof (struct decision)); - memset (new, 0, sizeof (*new)); new->success = *last; new->position = xstrdup (position); new->number = next_number++; @@ -332,14 +483,12 @@ new_decision (position, last) /* Create a new test and link it in at PLACE. */ static struct decision_test * -new_decision_test (type, pplace) - enum decision_type type; - struct decision_test ***pplace; +new_decision_test (enum decision_type type, struct decision_test ***pplace) { struct decision_test **place = *pplace; struct decision_test *test; - test = (struct decision_test *) xmalloc (sizeof (*test)); + test = xmalloc (sizeof (*test)); test->next = *place; test->type = type; *place = test; @@ -350,21 +499,21 @@ new_decision_test (type, pplace) return test; } -/* Search for and return operand N. */ +/* Search for and return operand N, stop when reaching node STOP. */ static rtx -find_operand (pattern, n) - rtx pattern; - int n; +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_INSN || code == MATCH_OPERAND || code == MATCH_OPERATOR || code == MATCH_PARALLEL) @@ -378,18 +527,19 @@ find_operand (pattern, n) switch (fmt[i]) { case 'e': case 'u': - if ((r = find_operand (XEXP (pattern, i), n)) != NULL_RTX) + if ((r = find_operand (XEXP (pattern, i), n, stop)) != NULL_RTX) return r; break; case 'V': if (! XVEC (pattern, i)) break; - /* FALLTHRU */ + /* Fall through. */ case 'E': for (j = 0; j < XVECLEN (pattern, i); j++) - if ((r = find_operand (XVECEXP (pattern, i, j), n)) != NULL_RTX) + if ((r = find_operand (XVECEXP (pattern, i, j), n, stop)) + != NULL_RTX) return r; break; @@ -408,9 +558,7 @@ find_operand (pattern, n) constraint for operand N. */ static rtx -find_matching_operand (pattern, n) - rtx pattern; - int n; +find_matching_operand (rtx pattern, int n) { const char *fmt; RTX_CODE code; @@ -438,7 +586,7 @@ find_matching_operand (pattern, n) case 'V': if (! XVEC (pattern, i)) break; - /* FALLTHRU */ + /* Fall through. */ case 'E': for (j = 0; j < XVECLEN (pattern, i); j++) @@ -463,11 +611,7 @@ find_matching_operand (pattern, n) '+' within a context that requires in-out constraints. */ static void -validate_pattern (pattern, insn, set, set_code) - rtx pattern; - rtx insn; - rtx set; - int set_code; +validate_pattern (rtx pattern, rtx insn, rtx set, int set_code) { const char *fmt; RTX_CODE code; @@ -479,14 +623,22 @@ validate_pattern (pattern, insn, set, set_code) { case MATCH_SCRATCH: return; - - case MATCH_INSN: + 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); - int allows_non_lvalue = 1, allows_non_const = 1; - int special_mode_pred = 0; + const struct pred_data *pred; const char *c_test; if (GET_CODE (insn) == DEFINE_INSN) @@ -496,122 +648,93 @@ validate_pattern (pattern, insn, set, set_code) if (pred_name[0] != 0) { - for (i = 0; i < NUM_KNOWN_PREDS; i++) - if (! strcmp (preds[i].name, pred_name)) - break; - - if (i < NUM_KNOWN_PREDS) - { - int j; + pred = lookup_predicate (pred_name); + if (!pred) + message_with_line (pattern_lineno, + "warning: unknown predicate '%s'", + pred_name); + } + else + pred = 0; - allows_non_lvalue = allows_non_const = 0; - for (j = 0; preds[i].codes[j] != 0; j++) - { - RTX_CODE c = preds[i].codes[j]; - if (c != LABEL_REF - && c != SYMBOL_REF - && c != CONST_INT - && c != CONST_DOUBLE - && c != CONST - && c != HIGH - && c != CONSTANT_P_RTX) - allows_non_const = 1; - - if (c != REG - && c != SUBREG - && c != MEM - && c != CONCAT - && c != PARALLEL - && c != STRICT_LOW_PART) - allows_non_lvalue = 1; - } - } - else + 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) { -#ifdef PREDICATE_CODES - /* If the port has a list of the predicates it uses but - omits one, warn. */ - message_with_line (pattern_lineno, - "warning: `%s' not in PREDICATE_CODES", - pred_name); -#endif + if (constraints0) + message_with_line (pattern_lineno, + "warning: constraints not supported in %s", + rtx_name[GET_CODE (insn)]); } - for (i = 0; i < NUM_SPECIAL_MODE_PREDS; ++i) - if (strcmp (pred_name, special_mode_pred_table[i]) == 0) - { - special_mode_pred = 1; - break; - } - } - - /* A MATCH_OPERAND that is a SET should have an output reload. */ - if (set && code == MATCH_OPERAND - && XSTR (pattern, 2)[0] != '\0') - { - if (set_code == '+') + /* A MATCH_OPERAND that is a SET should have an output reload. */ + else if (set && constraints0) { - if (XSTR (pattern, 2)[0] == '+') - ; - /* If we've only got an output reload for this operand, - we'd better have a matching input operand. */ - else if (XSTR (pattern, 2)[0] == '=' - && find_matching_operand (insn, XINT (pattern, 0))) - ; - else + 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 in-out reload", + "operand %d missing output reload", XINT (pattern, 0)); error_count++; } } - else if (XSTR (pattern, 2)[0] != '=' - && XSTR (pattern, 2)[0] != '+') - { - 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_name[0] != '\0' - && 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 - address_operand, since its mode is related to the mode of - the memory not the operand. Exclude the SET_DEST of a call - instruction, as that is a common idiom. */ + 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 - && allows_non_const - && ! special_mode_pred - && pred_name[0] != '\0' - && strcmp (pred_name, "address_operand") != 0 + && 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)); - } + message_with_line (pattern_lineno, + "warning: operand %d missing mode?", + XINT (pattern, 0)); return; } @@ -623,22 +746,22 @@ validate_pattern (pattern, insn, set, set_code) dest = SET_DEST (pattern); src = SET_SRC (pattern); - /* Find the referant for a DUP. */ + /* 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)); + 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)); - - /* 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); + src = find_operand (insn, XINT (src, 0), NULL); dmode = GET_MODE (dest); smode = GET_MODE (src); @@ -659,7 +782,7 @@ validate_pattern (pattern, insn, set, set_code) error_count++; } - /* If only one of the operands is VOIDmode, and PC or CC0 is + /* 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 @@ -746,20 +869,16 @@ validate_pattern (pattern, insn, set, set_code) A pointer to the final node in the chain is returned. */ static struct decision * -add_to_sequence (pattern, last, position, insn_type, top) - rtx pattern; - struct decision_head *last; - const char *position; - enum routine_type insn_type; - int top; +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; - register size_t i; - register const char *fmt; + size_t i; + const char *fmt; int depth = strlen (position); int len; enum machine_mode mode; @@ -767,7 +886,7 @@ add_to_sequence (pattern, last, position, insn_type, top) if (depth > max_depth) max_depth = depth; - subpos = (char *) xmalloc (depth + 2); + subpos = xmalloc (depth + 2); strcpy (subpos, position); subpos[depth + 1] = 0; @@ -781,7 +900,7 @@ add_to_sequence (pattern, last, position, insn_type, top) switch (code) { case PARALLEL: - /* Toplevel peephole pattern. */ + /* Toplevel peephole pattern. */ if (insn_type == PEEPHOLE2 && top) { /* We don't need the node we just created -- unlink it. */ @@ -790,7 +909,7 @@ add_to_sequence (pattern, last, position, insn_type, top) 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. */ + ever use 'A', however; it is always implied. */ subpos[depth] = (i > 0 ? 'A' + i : 0); sub = add_to_sequence (XVECEXP (pattern, 0, i), @@ -811,16 +930,15 @@ add_to_sequence (pattern, last, position, insn_type, top) beyond the end of the vector. */ test = new_decision_test (DT_veclen_ge, &place); test->u.veclen = XVECLEN (pattern, 2); - /* FALLTHRU */ + /* Fall through. */ case MATCH_OPERAND: case MATCH_SCRATCH: case MATCH_OPERATOR: - case MATCH_INSN: { - const char *pred_name; RTX_CODE was_code = code; - int allows_const_int = 1; + const char *pred_name; + bool allows_const_int = true; if (code == MATCH_SCRATCH) { @@ -838,46 +956,36 @@ add_to_sequence (pattern, last, position, insn_type, top) 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 and save its number. If - we do, and it only accepts one code, note that fact. The - predicate `const_int_operand' only tests for a CONST_INT, so - if we do so we can avoid calling it at all. - - Finally, if we know that the predicate does not allow - CONST_INT, we know that the only way the predicate can match - is if the modes match (here we use the kludge of relying on - the fact that "address_operand" accepts CONST_INT; otherwise, - it would have to be a special case), so we can test the mode - (but we need not). This fact should considerably simplify the - generated code. */ - - for (i = 0; i < NUM_KNOWN_PREDS; i++) - if (! strcmp (preds[i].name, pred_name)) - break; + /* See if we know about this predicate. + If we do, remember it for use below. - if (i < NUM_KNOWN_PREDS) + 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) { - int j; - - test->u.pred.index = i; - - if (preds[i].codes[1] == 0 && code == UNKNOWN) - code = preds[i].codes[0]; - - allows_const_int = 0; - for (j = 0; preds[i].codes[j] != 0; j++) - if (preds[i].codes[j] == CONST_INT) - { - allows_const_int = 1; - break; - } + 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 - test->u.pred.index = -1; + 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. */ @@ -992,7 +1100,7 @@ add_to_sequence (pattern, last, position, insn_type, top) case 'E': { - register int j; + int j; for (j = 0; j < XVECLEN (pattern, i); j++) { subpos[depth] = 'a' + j; @@ -1043,8 +1151,7 @@ add_to_sequence (pattern, last, position, insn_type, top) Returns > 0 for "definitely both true" and < 0 for "maybe both true". */ static int -maybe_both_true_2 (d1, d2) - struct decision_test *d1, *d2; +maybe_both_true_2 (struct decision_test *d1, struct decision_test *d2) { if (d1->type == d2->type) { @@ -1101,39 +1208,28 @@ maybe_both_true_2 (d1, d2) separate DT_mode that will make maybe_both_true_1 return 0. */ } - if (d1->u.pred.index >= 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) { - const RTX_CODE *c = &preds[d1->u.pred.index].codes[0]; - while (*c != 0) - { - if (*c == d2->u.code) - break; - ++c; - } - if (*c == 0) + 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.index >= 0) + else if (d2->type == DT_pred && d2->u.pred.data) { - const RTX_CODE *c1 = &preds[d1->u.pred.index].codes[0]; - int common = 0; + bool common = false; + enum rtx_code c; - while (*c1 != 0 && !common) - { - const RTX_CODE *c2 = &preds[d2->u.pred.index].codes[0]; - while (*c2 != 0 && !common) - { - common = (*c1 == *c2); - ++c2; - } - ++c1; - } + 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; @@ -1154,13 +1250,12 @@ maybe_both_true_2 (d1, d2) Returns > 0 for "definitely both true" and < 0 for "maybe both true". */ static int -maybe_both_true_1 (d1, d2) - struct decision_test *d1, *d2; +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 existance of a lone DT_accept_op test. */ + this by the existence of a lone DT_accept_op test. */ if (d1->type == DT_accept_op || d2->type == DT_accept_op) return 1; @@ -1185,13 +1280,12 @@ maybe_both_true_1 (d1, d2) 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 non-zero if we are to only look at the top level and not + TOPLEVEL is nonzero if we are to only look at the top level and not recursively descend. */ static int -maybe_both_true (d1, d2, toplevel) - struct decision *d1, *d2; - int toplevel; +maybe_both_true (struct decision *d1, struct decision *d2, + int toplevel) { struct decision *p1, *p2; int cmp; @@ -1218,7 +1312,7 @@ maybe_both_true (d1, d2, toplevel) if (cmp != 0) { if (toplevel) - abort(); + abort (); /* If the d2->position was lexically lower, swap. */ if (cmp > 0) @@ -1258,8 +1352,7 @@ maybe_both_true (d1, d2, toplevel) /* A subroutine of nodes_identical. Examine two tests for equivalence. */ static int -nodes_identical_1 (d1, d2) - struct decision_test *d1, *d2; +nodes_identical_1 (struct decision_test *d1, struct decision_test *d2) { switch (d1->type) { @@ -1302,12 +1395,11 @@ nodes_identical_1 (d1, d2) } /* True iff the two nodes are identical (on one level only). Due - to the way these lists are constructed, we shouldn't have to + to the way these lists are constructed, we shouldn't have to consider different orderings on the tests. */ static int -nodes_identical (d1, d2) - struct decision *d1, *d2; +nodes_identical (struct decision *d1, struct decision *d2) { struct decision_test *t1, *t2; @@ -1338,13 +1430,12 @@ nodes_identical (d1, d2) /* 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 + 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 (oldd, addd) - struct decision *oldd, *addd; +merge_accept_insn (struct decision *oldd, struct decision *addd) { struct decision_test *old, *add; @@ -1388,8 +1479,7 @@ merge_accept_insn (oldd, addd) /* Merge two decision trees OLDH and ADDH, modifying OLDH destructively. */ static void -merge_trees (oldh, addh) - struct decision_head *oldh, *addh; +merge_trees (struct decision_head *oldh, struct decision_head *addh) { struct decision *next, *add; @@ -1426,7 +1516,7 @@ merge_trees (oldh, addh) 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)) @@ -1468,13 +1558,12 @@ merge_trees (oldh, addh) } } -/* Walk the tree looking for sub-nodes that perform common tests. +/* 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 (head) - struct decision_head *head; +factor_tests (struct decision_head *head) { struct decision *first, *next; @@ -1490,7 +1579,7 @@ factor_tests (head) if (next->tests->type != type) continue; - /* Don't want all node types, just those we can turn into + /* Don't want all node types, just those we can turn into switch statements. */ if (type != DT_mode && type != DT_code @@ -1508,7 +1597,7 @@ factor_tests (head) 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; @@ -1559,8 +1648,7 @@ factor_tests (head) predicates, remove them. */ static void -simplify_tests (head) - struct decision_head *head; +simplify_tests (struct decision_head *head) { struct decision *tree; @@ -1597,9 +1685,7 @@ simplify_tests (head) that is generated. */ static int -break_out_subroutines (head, initial) - struct decision_head *head; - int initial; +break_out_subroutines (struct decision_head *head, int initial) { int size = 0; struct decision *sub; @@ -1619,13 +1705,11 @@ break_out_subroutines (head, initial) when p is true. */ static void -find_afterward (head, real_afterward) - struct decision_head *head; - struct decision *real_afterward; +find_afterward (struct decision_head *head, struct decision *real_afterward) { struct decision *p, *q, *afterward; - /* We can't propogate alternatives across subroutine boundaries. + /* We can't propagate alternatives across subroutine boundaries. This is not incorrect, merely a minor optimization loss. */ p = head->first; @@ -1638,7 +1722,7 @@ find_afterward (head, real_afterward) if (maybe_both_true (p, q, 1)) break; - /* If we reached the end of the list without finding one, + /* If we reached the end of the list without finding one, use the incoming afterward position. */ if (!q) q = afterward; @@ -1662,17 +1746,14 @@ find_afterward (head, 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 non-zero, otherwise return. + 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. */ + match multiple insns and we try to step past the end of the stream. */ static void -change_state (oldpos, newpos, afterward, indent) - const char *oldpos; - const char *newpos; - struct decision *afterward; - const char *indent; +change_state (const char *oldpos, const char *newpos, + struct decision *afterward, const char *indent) { int odepth = strlen (oldpos); int ndepth = strlen (newpos); @@ -1685,27 +1766,27 @@ change_state (oldpos, newpos, afterward, indent) /* Hunt for the last [A-Z] in both strings. */ for (old_has_insn = odepth - 1; old_has_insn >= 0; --old_has_insn) - if (oldpos[old_has_insn] >= 'A' && oldpos[old_has_insn] <= 'Z') + if (ISUPPER (oldpos[old_has_insn])) break; for (new_has_insn = ndepth - 1; new_has_insn >= 0; --new_has_insn) - if (newpos[new_has_insn] >= 'A' && newpos[new_has_insn] <= 'Z') + 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 (newpos[depth] >= 'A' && newpos[depth] <= 'Z') + /* It's a different insn from the first one. */ + if (ISUPPER (newpos[depth])) { /* We can only fail if we're moving down the tree. */ if (old_has_insn >= 0 && oldpos[old_has_insn] >= newpos[depth]) { - printf ("%stem = peep2_next_insn (%d);\n", + printf ("%stem = peep2_next_insn (%d);\n", indent, newpos[depth] - 'A'); } else { - printf ("%stem = peep2_next_insn (%d);\n", + printf ("%stem = peep2_next_insn (%d);\n", indent, newpos[depth] - 'A'); printf ("%sif (tem == NULL_RTX)\n", indent); if (afterward) @@ -1715,7 +1796,7 @@ change_state (oldpos, newpos, afterward, indent) } printf ("%sx%d = PATTERN (tem);\n", indent, depth + 1); } - else if (newpos[depth] >= 'a' && newpos[depth] <= 'z') + else if (ISLOWER (newpos[depth])) printf ("%sx%d = XVECEXP (x%d, 0, %d);\n", indent, depth + 1, depth, newpos[depth] - 'a'); else @@ -1729,10 +1810,9 @@ change_state (oldpos, newpos, afterward, indent) the name. */ static void -print_code (code) - enum rtx_code code; +print_code (enum rtx_code code) { - register const char *p; + const char *p; for (p = GET_RTX_NAME (code); *p; p++) putchar (TOUPPER (*p)); } @@ -1740,10 +1820,8 @@ print_code (code) /* Emit code to cross an afterward link -- change state and branch. */ static void -write_afterward (start, afterward, indent) - struct decision *start; - struct decision *afterward; - const char *indent; +write_afterward (struct decision *start, struct decision *afterward, + const char *indent) { if (!afterward || start->subroutine_number > 0) printf("%sgoto ret0;\n", indent); @@ -1754,13 +1832,25 @@ write_afterward (start, afterward, indent) } } -/* Emit a switch statement, if possible, for an initial sequence of +/* 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 (start, depth) - struct decision *start; - int depth; +write_switch (struct decision *start, int depth) { struct decision *p = start; enum decision_type type = p->tests->type; @@ -1788,7 +1878,7 @@ write_switch (start, depth) printf (" switch (GET_CODE (x%d))\n {\n", depth); code = p->tests->u.code; - do + do { if (p != start && p->need_label && needs_label == NULL) needs_label = p; @@ -1821,22 +1911,22 @@ write_switch (start, depth) else ret = p; - while (p && p->tests->type == DT_pred - && p->tests->u.pred.index >= 0) + while (p && p->tests->type == DT_pred && p->tests->u.pred.data) { - const RTX_CODE *c; - - for (c = &preds[p->tests->u.pred.index].codes[0]; *c ; ++c) - if (codemap[(int) *c] != 0) + 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 = &preds[p->tests->u.pred.index].codes[0]; *c ; ++c) - { - printf (" case "); - print_code (*c); - printf (":\n"); - codemap[(int) *c] = 1; - } + 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; @@ -1869,7 +1959,16 @@ write_switch (start, depth) || type == DT_elt_one_int || type == DT_elt_zero_wide_safe) { - printf (" switch ("); + 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: @@ -1892,7 +1991,7 @@ write_switch (start, depth) default: abort (); } - printf (")\n {\n"); + printf (")\n%s {\n", indent); do { @@ -1907,7 +2006,7 @@ write_switch (start, depth) if (p != start && p->need_label && needs_label == NULL) needs_label = p; - printf (" case "); + printf ("%s case ", indent); switch (type) { case DT_mode: @@ -1920,12 +2019,12 @@ write_switch (start, depth) case DT_elt_one_int: case DT_elt_zero_wide: case DT_elt_zero_wide_safe: - printf (HOST_WIDE_INT_PRINT_DEC, p->tests->u.intval); + print_host_wide_int (p->tests->u.intval); break; default: abort (); } - printf (":\n goto L%d;\n", p->success.first->number); + printf (":\n%s goto L%d;\n", indent, p->success.first->number); p->success.first->need_label = 1; p = p->next; @@ -1933,13 +2032,14 @@ write_switch (start, depth) while (p && p->tests->type == type && !p->tests->next); case_done: - printf (" default:\n break;\n }\n"); + 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 ameanable. */ + /* None of the other tests are amenable. */ return p; } } @@ -1947,10 +2047,8 @@ write_switch (start, depth) /* Emit code for one test. */ static void -write_cond (p, depth, subroutine_type) - struct decision_test *p; - int depth; - enum routine_type subroutine_type; +write_cond (struct decision_test *p, int depth, + enum routine_type subroutine_type) { switch (p->type) { @@ -1978,7 +2076,12 @@ write_cond (p, depth, subroutine_type) case DT_elt_zero_wide: case DT_elt_zero_wide_safe: printf ("XWINT (x%d, 0) == ", depth); - printf (HOST_WIDE_INT_PRINT_DEC, p->u.intval); + 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: @@ -2022,12 +2125,9 @@ write_cond (p, depth, subroutine_type) perform a state change. For the `accept' tests we must do more work. */ static void -write_action (p, test, depth, uncond, success, subroutine_type) - struct decision *p; - struct decision_test *test; - int depth, uncond; - struct decision *success; - enum routine_type subroutine_type; +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; @@ -2068,11 +2168,13 @@ write_action (p, test, depth, uncond, success, subroutine_type) 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;\n", indent, test->u.insn.code_number); + printf ("%sreturn %d; /* %s */\n", indent, + test->u.insn.code_number, + insn_name_ptr[test->u.insn.code_number]); break; case SPLIT: - printf ("%sreturn gen_split_%d (operands);\n", + printf ("%sreturn gen_split_%d (insn, operands);\n", indent, test->u.insn.code_number); break; @@ -2081,7 +2183,7 @@ write_action (p, test, depth, uncond, success, subroutine_type) int match_len = 0, i; for (i = strlen (p->position) - 1; i >= 0; --i) - if (p->position[i] >= 'A' && p->position[i] <= 'Z') + if (ISUPPER (p->position[i])) { match_len = p->position[i] - 'A'; break; @@ -2113,9 +2215,7 @@ write_action (p, test, depth, uncond, success, subroutine_type) /* ??? is_unconditional is a stupid name for a tri-state function. */ static int -is_unconditional (t, subroutine_type) - struct decision_test *t; - enum routine_type subroutine_type; +is_unconditional (struct decision_test *t, enum routine_type subroutine_type) { if (t->type == DT_accept_op) return 1; @@ -2142,14 +2242,29 @@ is_unconditional (t, subroutine_type) Return true if there is no fallthru path. */ static int -write_node (p, depth, subroutine_type) - struct decision *p; - int depth; - enum routine_type subroutine_type; +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) @@ -2159,11 +2274,8 @@ write_node (p, depth, subroutine_type) while ((test = test->next) != NULL) { - int uncond2; - last_test = test; - uncond2 = is_unconditional (test, subroutine_type); - if (uncond2 != 0) + if (is_unconditional (test, subroutine_type)) break; printf ("\n && "); @@ -2181,10 +2293,8 @@ write_node (p, depth, subroutine_type) /* Emit code for all of the sibling nodes of HEAD. */ static void -write_tree_1 (head, depth, subroutine_type) - struct decision_head *head; - int depth; - enum routine_type subroutine_type; +write_tree_1 (struct decision_head *head, int depth, + enum routine_type subroutine_type) { struct decision *p, *next; int uncond = 0; @@ -2217,13 +2327,10 @@ write_tree_1 (head, depth, subroutine_type) position at the node that branched to this node. */ static void -write_tree (head, prevpos, type, initial) - struct decision_head *head; - const char *prevpos; - enum routine_type type; - int initial; +write_tree (struct decision_head *head, const char *prevpos, + enum routine_type type, int initial) { - register struct decision *p = head->first; + struct decision *p = head->first; putchar ('\n'); if (p->need_label) @@ -2277,15 +2384,13 @@ write_tree (head, prevpos, type, initial) node TREE. */ static void -write_subroutine (head, type) - struct decision_head *head; - enum routine_type type; +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) @@ -2298,34 +2403,24 @@ write_subroutine (head, type) switch (type) { case RECOG: - printf ("%sint recog%s PARAMS ((rtx, rtx, int *));\n", s_or_e, extension); printf ("%sint\n\ -recog%s (x0, insn, pnum_clobbers)\n\ - register rtx x0;\n\ - rtx insn ATTRIBUTE_UNUSED;\n\ - int *pnum_clobbers ATTRIBUTE_UNUSED;\n", s_or_e, extension); +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 split%s PARAMS ((rtx, rtx));\n", s_or_e, extension); printf ("%srtx\n\ -split%s (x0, insn)\n\ - register rtx x0;\n\ - rtx insn ATTRIBUTE_UNUSED;\n", s_or_e, extension); +split%s (rtx x0 ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED)\n", + s_or_e, extension); break; case PEEPHOLE2: - printf ("%srtx peephole2%s PARAMS ((rtx, rtx, int *));\n", - s_or_e, extension); printf ("%srtx\n\ -peephole2%s (x0, insn, _pmatch_len)\n\ - register rtx x0;\n\ - rtx insn ATTRIBUTE_UNUSED;\n\ - int *_pmatch_len ATTRIBUTE_UNUSED;\n", s_or_e, extension); +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 register rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];\n"); + printf ("{\n rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];\n"); for (i = 1; i <= max_depth; i++) - printf (" register rtx x%d ATTRIBUTE_UNUSED;\n", i); + printf (" rtx x%d ATTRIBUTE_UNUSED;\n", i); printf (" %s tem ATTRIBUTE_UNUSED;\n", IS_SPLIT (type) ? "rtx" : "int"); @@ -2344,9 +2439,7 @@ peephole2%s (x0, insn, _pmatch_len)\n\ subroutines, but did not write them out. Do so now. */ static void -write_subroutines (head, type) - struct decision_head *head; - enum routine_type type; +write_subroutines (struct decision_head *head, enum routine_type type) { struct decision *p; @@ -2361,7 +2454,7 @@ write_subroutines (head, type) /* Begin the output file. */ static void -write_header () +write_header (void) { puts ("\ /* Generated automatically by the program `genrecog' from the target\n\ @@ -2369,6 +2462,8 @@ write_header () \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\ @@ -2380,6 +2475,7 @@ write_header () #include \"hard-reg-set.h\"\n\ #include \"resource.h\"\n\ #include \"toplev.h\"\n\ +#include \"reload.h\"\n\ \n"); puts ("\n\ @@ -2405,10 +2501,10 @@ write_header () puts ("\n\ The function split_insns returns 0 if the rtl could not\n\ - be split or the split rtl in a SEQUENCE if it can be.\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 a SEQUENCE,\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"); } @@ -2420,17 +2516,20 @@ write_header () TYPE says what type of routine we are recognizing (RECOG or SPLIT). */ static struct decision_head -make_insn_sequence (insn, type) - rtx insn; - enum routine_type type; +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. */ + if (truth == 0) + abort (); + record_insn_name (next_insn_code, (type == RECOG ? XSTR (insn, 0) : NULL)); c_test_pos[0] = '\0'; @@ -2478,7 +2577,8 @@ make_insn_sequence (insn, type) continue; place = &test->next; - if (c_test[0]) + /* 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) @@ -2498,7 +2598,7 @@ make_insn_sequence (insn, type) switch (type) { case RECOG: - /* If this is an DEFINE_INSN and X is a PARALLEL, see if it ends + /* 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. */ @@ -2511,7 +2611,7 @@ make_insn_sequence (insn, type) { rtx y = XVECEXP (x, 0, i - 1); if (GET_CODE (y) != CLOBBER - || (GET_CODE (XEXP (y, 0)) != REG + || (!REG_P (XEXP (y, 0)) && GET_CODE (XEXP (y, 0)) != MATCH_SCRATCH)) break; } @@ -2551,7 +2651,9 @@ make_insn_sequence (insn, type) place = &last->tests; } - if (c_test[0]) + /* 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; @@ -2569,12 +2671,12 @@ make_insn_sequence (insn, type) case SPLIT: /* Define the subroutine we will call below and emit in genemit. */ - printf ("extern rtx gen_split_%d PARAMS ((rtx *));\n", next_insn_code); + 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 PARAMS ((rtx, rtx *));\n", + printf ("extern rtx gen_peephole2_%d (rtx, rtx *);\n", next_insn_code); break; } @@ -2583,9 +2685,7 @@ make_insn_sequence (insn, type) } static void -process_tree (head, subroutine_type) - struct decision_head *head; - enum routine_type subroutine_type; +process_tree (struct decision_head *head, enum routine_type subroutine_type) { if (head->first == NULL) { @@ -2612,12 +2712,10 @@ process_tree (head, subroutine_type) write_subroutine (head, subroutine_type); } -extern int main PARAMS ((int, char **)); +extern int main (int, char **); int -main (argc, argv) - int argc; - char **argv; +main (int argc, char **argv) { rtx desc; struct decision_head recog_tree, split_tree, peephole2_tree, h; @@ -2628,14 +2726,10 @@ main (argc, argv) memset (&split_tree, 0, sizeof split_tree); memset (&peephole2_tree, 0, sizeof peephole2_tree); - if (argc <= 1) - fatal ("No input file name."); - - if (init_md_reader (argv[1]) != SUCCESS_EXIT_CODE) + if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE) return (FATAL_EXIT_CODE); next_insn_code = 0; - next_index = 0; write_header (); @@ -2647,26 +2741,33 @@ main (argc, argv) if (desc == NULL) break; - if (GET_CODE (desc) == DEFINE_INSN) + 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); - } - else if (GET_CODE (desc) == DEFINE_SPLIT) - { + break; + + case DEFINE_SPLIT: h = make_insn_sequence (desc, SPLIT); merge_trees (&split_tree, &h); - } - else if (GET_CODE (desc) == DEFINE_PEEPHOLE2) - { + break; + + case DEFINE_PEEPHOLE2: h = make_insn_sequence (desc, PEEPHOLE2); merge_trees (&peephole2_tree, &h); + + default: + /* do nothing */; } - - next_index++; } - if (error_count) + if (error_count || have_error) return FATAL_EXIT_CODE; puts ("\n\n"); @@ -2681,8 +2782,7 @@ main (argc, argv) /* Define this so we can link with print-rtl.o to get debug_rtx function. */ const char * -get_insn_name (code) - int code; +get_insn_name (int code) { if (code < insn_name_ptr_size) return insn_name_ptr[code]; @@ -2691,9 +2791,7 @@ get_insn_name (code) } static void -record_insn_name (code, name) - int code; - const char *name; +record_insn_name (int code, const char *name) { static const char *last_real_name = "insn"; static int last_real_code = 0; @@ -2703,9 +2801,8 @@ record_insn_name (code, name) { int new_size; new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512); - insn_name_ptr = - (char **) xrealloc (insn_name_ptr, sizeof(char *) * new_size); - memset (insn_name_ptr + insn_name_ptr_size, 0, + insn_name_ptr = xrealloc (insn_name_ptr, sizeof(char *) * new_size); + memset (insn_name_ptr + insn_name_ptr_size, 0, sizeof(char *) * (new_size - insn_name_ptr_size)); insn_name_ptr_size = new_size; } @@ -2720,13 +2817,12 @@ record_insn_name (code, name) last_real_name = new = xstrdup (name); last_real_code = code; } - + insn_name_ptr[code] = new; -} +} static void -debug_decision_2 (test) - struct decision_test *test; +debug_decision_2 (struct decision_test *test) { switch (test->type) { @@ -2746,12 +2842,10 @@ debug_decision_2 (test) fprintf (stderr, "elt1_i=%d", (int) test->u.intval); break; case DT_elt_zero_wide: - fprintf (stderr, "elt0_w="); - fprintf (stderr, HOST_WIDE_INT_PRINT_DEC, test->u.intval); + fprintf (stderr, "elt0_w=" HOST_WIDE_INT_PRINT_DEC, test->u.intval); break; case DT_elt_zero_wide_safe: - fprintf (stderr, "elt0_ws="); - fprintf (stderr, HOST_WIDE_INT_PRINT_DEC, test->u.intval); + fprintf (stderr, "elt0_ws=" HOST_WIDE_INT_PRINT_DEC, test->u.intval); break; case DT_veclen_ge: fprintf (stderr, "veclen>=%d", test->u.veclen); @@ -2775,7 +2869,7 @@ debug_decision_2 (test) fprintf (stderr, "A_op=%d", test->u.opno); break; case DT_accept_insn: - fprintf (stderr, "A_insn=(%d,%d)", + fprintf (stderr, "A_insn=(%d,%d)", test->u.insn.code_number, test->u.insn.num_clobbers_to_add); break; @@ -2785,9 +2879,7 @@ debug_decision_2 (test) } static void -debug_decision_1 (d, indent) - struct decision *d; - int indent; +debug_decision_1 (struct decision *d, int indent) { int i; struct decision_test *test; @@ -2820,9 +2912,7 @@ debug_decision_1 (d, indent) } static void -debug_decision_0 (d, indent, maxdepth) - struct decision *d; - int indent, maxdepth; +debug_decision_0 (struct decision *d, int indent, int maxdepth) { struct decision *n; int i; @@ -2843,15 +2933,13 @@ debug_decision_0 (d, indent, maxdepth) } void -debug_decision (d) - struct decision *d; +debug_decision (struct decision *d) { debug_decision_0 (d, 0, 1000000); } void -debug_decision_list (d) - struct decision *d; +debug_decision_list (struct decision *d) { while (d) {