/* 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, 2005, 2007, 2008, 2009
+ 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
- the Free Software Foundation; either version 2, or (at your option)
+ 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 3, 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 COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
/* This program is used to produce insn-recog.c, which contains a
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))
-/* Holds an array of names indexed by insn_code_number. */
-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
struct decision *first;
struct decision *last;
};
-
+
+/* 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
+};
+
/* 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. */
/* 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_mode, DT_code, DT_veclen,
- DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide,
- DT_dup, DT_pred, DT_c_test,
- DT_accept_op, DT_accept_insn
- } type;
+ enum decision_type 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. */
- 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;
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. */
/* Count of errors. */
static int error_count;
\f
-/* 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))
+
+/* 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;
-static struct pred_table
+
+ 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)
{
- 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 = XCNEW (struct pred_data);
+ char codes[NUM_RTX_CODE];
+ 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)
+ add_predicate_code (pred, (enum rtx_code) i);
+ add_predicate (pred);
+}
+#undef I
+#undef N
+#undef Y
+
+\f
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
+ (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 *, 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));
-
-static void record_insn_name
- PARAMS ((int, const char *));
+ (struct decision_head *, enum routine_type);
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 *);
\f
/* 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_decision = XCNEW (struct decision);
- memset (new, 0, sizeof (*new));
- new->success = *last;
- new->position = xstrdup (position);
- new->number = next_number++;
+ new_decision->success = *last;
+ new_decision->position = xstrdup (position);
+ new_decision->number = next_number++;
- last->first = last->last = new;
- return new;
+ last->first = last->last = new_decision;
+ return new_decision;
}
/* 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 = XNEW (struct decision_test);
test->next = *place;
test->type = type;
*place = test;
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)
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;
+ /* 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;
break;
default:
- abort ();
+ 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 (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;
{
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)
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;
-
- 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
- {
-#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
- }
-
- for (i = 0; i < NUM_SPECIAL_MODE_PREDS; ++i)
- if (strcmp (pred_name, special_mode_pred_table[i]) == 0)
- {
- special_mode_pred = 1;
- break;
- }
+ pred = lookup_predicate (pred_name);
+ if (!pred)
+ message_with_line (pattern_lineno,
+ "warning: unknown predicate '%s'",
+ pred_name);
}
+ else
+ pred = 0;
- /* A MATCH_OPERAND that is a SET should have an output reload. */
- if (set && code == MATCH_OPERAND)
+ if (code == MATCH_OPERAND)
{
- if (set_code == '+'
- && XSTR (pattern, 2)[0] != '\0'
- && XSTR (pattern, 2)[0] != '+')
+ 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)
{
- message_with_line (pattern_lineno,
- "operand %d missing in-out reload",
- XINT (pattern, 0));
- error_count++;
+ if (constraints0)
+ message_with_line (pattern_lineno,
+ "warning: constraints not supported in %s",
+ rtx_name[GET_CODE (insn)]);
}
- else if (XSTR (pattern, 2)[0] != '\0'
- && XSTR (pattern, 2)[0] != '='
- && XSTR (pattern, 2)[0] != '+')
+
+ /* A MATCH_OPERAND that is a SET should have an output reload. */
+ else if (set && constraints0)
{
- message_with_line (pattern_lineno,
- "operand %d missing output reload",
- XINT (pattern, 0));
- error_count++;
+ 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_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;
}
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);
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
&& GET_CODE (dest) != CC0
&& GET_CODE (src) != PC
&& GET_CODE (src) != CC0
- && GET_CODE (src) != CONST_INT)
+ && !CONST_INT_P (src)
+ && GET_CODE (src) != CALL)
{
const char *which;
which = (dmode == VOIDmode ? "destination" : "source");
case STRICT_LOW_PART:
validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0);
- validate_pattern (XEXP (pattern, 1), insn, NULL, 0);
return;
case LABEL_REF:
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
}
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 *this_decision, *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;
if (depth > max_depth)
max_depth = depth;
- subpos = (char *) alloca (depth + 2);
+ subpos = XNEWVAR (char, depth + 2);
strcpy (subpos, position);
subpos[depth + 1] = 0;
- sub = this = new_decision (position, last);
- place = &this->tests;
+ sub = this_decision = new_decision (position, last);
+ place = &this_decision->tests;
restart:
mode = GET_MODE (pattern);
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. */
- last->first = last->last = NULL;
+ 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. */
+ 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;
}
- return sub;
+ 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:
- case MATCH_PARALLEL:
- 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)
{
code = UNKNOWN;
}
- /* We know exactly what const_int_operand matches -- any CONST_INT. */
- if (strcmp ("const_int_operand", pred_name) == 0)
- {
- code = CONST_INT;
- mode = VOIDmode;
- }
- else if (pred_name[0] != 0)
+ 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. */
if (allows_const_int)
mode = VOIDmode;
- /* Accept the operand, ie. record it in `operands'. */
+ /* Accept the operand, i.e. record it in `operands'. */
test = new_decision_test (DT_accept_op, &place);
test->u.opno = XINT (pattern, 0);
{
if (fmt[i] == 'i')
{
- if (i == 0)
+ gcc_assert (i < 2);
+
+ if (!i)
{
test = new_decision_test (DT_elt_zero_int, &place);
test->u.intval = XINT (pattern, i);
}
- else if (i == 1)
+ else
{
test = new_decision_test (DT_elt_one_int, &place);
test->u.intval = XINT (pattern, i);
}
- else
- abort ();
}
else if (fmt[i] == 'w')
{
- if (i != 0)
- abort ();
+ /* 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;
- test = new_decision_test (DT_elt_zero_wide, &place);
+ gcc_assert (!i);
+
+ test = new_decision_test (type, &place);
test->u.intval = XWINT (pattern, i);
}
else if (fmt[i] == 'E')
{
- if (i != 0)
- abort ();
+ gcc_assert (!i);
test = new_decision_test (DT_veclen, &place);
test->u.veclen = XVECLEN (pattern, i);
case 'E':
{
- register int j;
+ int j;
for (j = 0; j < XVECLEN (pattern, i); j++)
{
subpos[depth] = 'a' + j;
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
before any of the nodes we may have added above. */
if (code != UNKNOWN)
{
- place = &this->tests;
+ place = &this_decision->tests;
test = new_decision_test (DT_code, &place);
test->u.code = code;
}
if (mode != VOIDmode)
{
- place = &this->tests;
+ place = &this_decision->tests;
test = new_decision_test (DT_mode, &place);
test->u.mode = mode;
}
/* If we didn't insert any tests or accept nodes, hork. */
- if (this->tests == NULL)
- abort ();
+ gcc_assert (this_decision->tests);
+ ret:
+ free (subpos);
return sub;
}
\f
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)
{
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_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:
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;
+ int 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;
}
}
+ /* 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;
}
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;
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;
cmp = strcmp (d1->position, d2->position);
if (cmp != 0)
{
- if (toplevel)
- abort();
+ 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 0;
+ return 1;
for (p1 = d1->success.first; p1; p1 = p1->next)
if (maybe_both_true (p1, d2, 0))
return 1;
/* 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)
{
+ case DT_num_insns:
+ return d1->u.num_insns == d2->u.num_insns;
+
case DT_mode:
return d1->u.mode == d2->u.mode;
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:
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 1;
default:
- abort ();
+ 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
+ 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;
return 0;
/* Check that their subnodes are at the same position, as any one set
- of sibling decisions must be at the same position. */
+ 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))
/* 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;
/* 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;
}
/* Trying to merge bits at different positions isn't possible. */
- if (strcmp (oldh->first->position, addh->first->position))
- abort ();
+ gcc_assert (!strcmp (oldh->first->position, addh->first->position));
for (add = addh->first; add ; add = next)
{
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))
how expensive/important the test is. Given that the tests
are also ordered within the list, examining the first is
sufficient. */
- if (add->tests->type < old->tests->type)
+ if ((int) add->tests->type < (int) old->tests->type)
insert_before = old;
}
}
}
\f
-/* 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;
for (first = head->first; first && first->next; first = next)
{
enum decision_type type;
- struct decision *new, *old_last;
+ struct decision *new_dec, *old_last;
type = first->tests->type;
next = first->next;
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
&& type != DT_veclen
&& type != DT_elt_zero_int
&& type != DT_elt_one_int
- && type != DT_elt_zero_wide)
+ && 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;
+ new_dec = new_decision (first->position, &first->success);
+ new_dec->tests = first->tests->next;
first->tests->next = NULL;
}
-
+
/* Crop the node tree off after our first test. */
first->next = NULL;
old_last = head->last;
if (next->tests->next != NULL)
{
- new = new_decision (next->position, &next->success);
- new->tests = next->tests->next;
+ new_dec = new_decision (next->position, &next->success);
+ new_dec->tests = next->tests->next;
next->tests->next = NULL;
}
- new = next;
+ new_dec = next;
next = next->next;
- new->next = NULL;
- h.first = h.last = new;
+ new_dec->next = NULL;
+ h.first = h.last = new_dec;
merge_trees (head, &h);
}
predicates, remove them. */
static void
-simplify_tests (head)
- struct decision_head *head;
+simplify_tests (struct decision_head *head)
{
struct decision *tree;
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;
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;
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;
\f
/* 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, const char *indent)
{
int odepth = strlen (oldpos);
int ndepth = strlen (newpos);
/* 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",
- indent, newpos[depth] - 'A');
- }
- else
- {
- printf ("%stem = peep2_next_insn (%d);\n",
- indent, newpos[depth] - 'A');
- printf ("%sif (tem == NULL_RTX)\n", indent);
- if (afterward)
- printf ("%s goto L%d;\n", indent, afterward->number);
- else
- printf ("%s goto ret0;\n", indent);
- }
+ printf ("%stem = peep2_next_insn (%d);\n",
+ indent, newpos[depth] - 'A');
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
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));
}
/* 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);
else
{
- change_state (start->position, afterward->position, NULL, indent);
+ change_state (start->position, afterward->position, indent);
printf ("%sgoto L%d;\n", indent, afterward->number);
}
}
-/* 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;
if (!p->next
|| p->tests->next
|| p->next->tests->type != type
- || p->next->tests->next)
+ || 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
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;
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;
+ const struct pred_data *data = p->tests->u.pred.data;
+ int c;
- for (c = &preds[p->tests->u.pred.index].codes[0]; *c ; ++c)
- if (codemap[(int) *c] != 0)
+ 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 ((enum rtx_code) c);
+ fputs (":\n", stdout);
+ codemap[c] = 1;
+ }
printf (" goto L%d;\n", p->number);
p->need_label = 1;
|| type == DT_veclen
|| type == DT_elt_zero_int
|| type == DT_elt_one_int
- || type == DT_elt_zero_wide)
+ || 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:
case DT_elt_one_int:
printf ("XINT (x%d, 1)", depth);
break;
- case DT_elt_zero_wide:
+ 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:
- abort ();
+ gcc_unreachable ();
}
- printf (")\n {\n");
+ 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 (" case ");
+ printf ("%s case ", indent);
switch (type)
{
case DT_mode:
case DT_elt_zero_int:
case DT_elt_one_int:
case DT_elt_zero_wide:
- printf (HOST_WIDE_INT_PRINT_DEC, p->tests->u.intval);
+ case DT_elt_zero_wide_safe:
+ print_host_wide_int (p->tests->u.intval);
break;
default:
- abort ();
+ gcc_unreachable ();
}
- 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;
}
while (p && p->tests->type == type && !p->tests->next);
-
- printf (" default:\n break;\n }\n");
+
+ 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 ameanable. */
+ /* None of the other tests are amenable. */
return p;
}
}
/* 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)
{
+ 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;
break;
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:
+ printf ("XVECLEN (x%d, 0) >= %d", depth, p->u.veclen);
break;
case DT_dup:
break;
case DT_c_test:
- printf ("(%s)", p->u.c_test);
+ print_c_condition (p->u.c_test);
break;
case DT_accept_insn:
- switch (subroutine_type)
- {
- case RECOG:
- if (p->u.insn.num_clobbers_to_add == 0)
- abort ();
- printf ("pnum_clobbers != NULL");
- break;
-
- default:
- abort ();
- }
+ gcc_assert (subroutine_type == RECOG);
+ gcc_assert (p->u.insn.num_clobbers_to_add);
+ printf ("pnum_clobbers != NULL");
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
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;
if (test->next)
{
test = test->next;
- if (test->type != DT_accept_insn)
- abort ();
+ gcc_assert (test->type == DT_accept_insn);
}
}
/* Sanity check that we're now at the end of the list of tests. */
- if (test->next)
- abort ();
+ gcc_assert (!test->next);
if (test->type == DT_accept_insn)
{
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,
+ get_insn_name (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;
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;
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
else
/* ??? 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;
case PEEPHOLE2:
return -1;
default:
- abort ();
+ gcc_unreachable ();
}
}
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)
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 && ");
/* 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;
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)
else
printf (" if (tem >= 0)\n return tem;\n");
- change_state (p->position, p->afterward->position, NULL, " ");
+ change_state (p->position, p->afterward->position, " ");
printf (" goto L%d;\n", p->afterward->number);
}
else
{
int depth = strlen (p->position);
- change_state (prevpos, p->position, head->last->afterward, " ");
+ change_state (prevpos, p->position, " ");
write_tree_1 (head, depth, type);
for (p = head->first; p; p = p->next)
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)
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");
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;
/* Begin the output file. */
static void
-write_header ()
+write_header (void)
{
puts ("\
/* Generated automatically by the program `genrecog' from the target\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 \"flags.h\"\n\
#include \"hard-reg-set.h\"\n\
#include \"resource.h\"\n\
+#include \"toplev.h\"\n\
+#include \"reload.h\"\n\
+#include \"regs.h\"\n\
+#include \"tm-constrs.h\"\n\
\n");
puts ("\n\
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");
}
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];
- record_insn_name (next_insn_code, (type == RECOG ? XSTR (insn, 0) : NULL));
+ /* 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)
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)
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. */
{
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;
}
if (i != XVECLEN (x, 0))
{
- rtx new;
+ rtx new_rtx;
struct decision_head clobber_head;
/* Build a similar insn without the clobbers. */
if (i == 1)
- new = XVECEXP (x, 0, 0);
+ new_rtx = XVECEXP (x, 0, 0);
else
{
int j;
- new = rtx_alloc (PARALLEL);
- XVEC (new, 0) = rtvec_alloc (i);
+ new_rtx = rtx_alloc (PARALLEL);
+ XVEC (new_rtx, 0) = rtvec_alloc (i);
for (j = i - 1; j >= 0; j--)
- XVECEXP (new, 0, j) = XVECEXP (x, 0, j);
+ XVECEXP (new_rtx, 0, j) = XVECEXP (x, 0, j);
}
/* Recognize it. */
memset (&clobber_head, 0, sizeof(clobber_head));
- last = add_to_sequence (new, &clobber_head, "", type, 1);
+ last = add_to_sequence (new_rtx, &clobber_head, "", type, 1);
/* Find the end of the test chain on the last node. */
for (test = last->tests; test->next; test = test->next)
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;
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;
}
}
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)
{
write_subroutine (head, subroutine_type);
}
\f
-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;
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 ();
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");
return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
}
\f
-/* Define this so we can link with print-rtl.o to get debug_rtx function. */
-const char *
-get_insn_name (code)
- int code;
-{
- if (code < insn_name_ptr_size)
- return insn_name_ptr[code];
- else
- return NULL;
-}
-
static void
-record_insn_name (code, name)
- int code;
- const char *name;
-{
- static const char *last_real_name = "insn";
- static int last_real_code = 0;
- char *new;
-
- if (insn_name_ptr_size <= code)
- {
- int new_size;
- new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
- insn_name_ptr =
- (char **) xrealloc (insn_name_ptr, sizeof(char *) * new_size);
- memset (insn_name_ptr + insn_name_ptr_size, 0,
- sizeof(char *) * (new_size - insn_name_ptr_size));
- insn_name_ptr_size = new_size;
- }
-
- if (!name || name[0] == '\0')
- {
- new = xmalloc (strlen (last_real_name) + 10);
- sprintf (new, "%s+%d", last_real_name, code - last_real_code);
- }
- else
- {
- last_real_name = new = xstrdup (name);
- last_real_code = code;
- }
-
- insn_name_ptr[code] = new;
-}
-\f
-static void
-debug_decision_2 (test)
- struct decision_test *test;
+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;
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=" 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);
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;
default:
- abort ();
+ gcc_unreachable ();
}
}
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;
}
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;
}
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)
{