X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fgenattrtab.c;h=793841befcb1be0ff5bea8d7326857c0866b107a;hb=4ad85520b09e3dd51e2e0195214b6a8be900bcc0;hp=7024c01793b8c0603b102e9bc64de684ccc2598c;hpb=139c3f48a40399b7fc3f76d0f5d5ef78da8b3c8d;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c index 7024c01793b..793841befcb 100644 --- a/gcc/genattrtab.c +++ b/gcc/genattrtab.c @@ -1,6 +1,6 @@ /* Generate code from machine description to compute values of attributes. Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003 Free Software Foundation, Inc. + 1999, 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) This file is part of GCC. @@ -21,7 +21,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This program handles insn attributes and the DEFINE_DELAY and - DEFINE_FUNCTION_UNIT definitions. + DEFINE_INSN_RESERVATION definitions. It produces a series of functions named `get_attr_...', one for each insn attribute. Each of these is given the rtx for an insn and returns a member @@ -54,7 +54,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA used. Internal attributes are defined to handle DEFINE_DELAY and - DEFINE_FUNCTION_UNIT. Special routines are output for these cases. + DEFINE_INSN_RESERVATION. Special routines are output for these cases. This program works by keeping a list of possible values for each attribute. These include the basic attribute choices, default values for attribute, and @@ -70,9 +70,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA indicates when the attribute has the specified value for the insn. This avoids recursive calls during compilation. - The strategy used when processing DEFINE_DELAY and DEFINE_FUNCTION_UNIT - definitions is to create arbitrarily complex expressions and have the - optimization simplify them. + The strategy used when processing DEFINE_DELAY definitions is to create + arbitrarily complex expressions and have the optimization simplify them. Once optimization is complete, any required routines and definitions will be written. @@ -90,15 +89,20 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA independent of the insn code. `in_struct' (ATTR_CURR_SIMPLIFIED_P): This rtx is fully simplified for the insn code currently being processed (see optimize_attrs). - `integrated' (ATTR_PERMANENT_P): This rtx is permanent and unique - (see attr_rtx). - `volatil' (ATTR_EQ_ATTR_P): During simplify_by_exploding the value of an - EQ_ATTR rtx is true if !volatil and false if volatil. */ + `return_val' (ATTR_PERMANENT_P): This rtx is permanent and unique + (see attr_rtx). */ #define ATTR_IND_SIMPLIFIED_P(RTX) (RTX_FLAG((RTX), unchanging)) #define ATTR_CURR_SIMPLIFIED_P(RTX) (RTX_FLAG((RTX), in_struct)) -#define ATTR_PERMANENT_P(RTX) (RTX_FLAG((RTX), integrated)) -#define ATTR_EQ_ATTR_P(RTX) (RTX_FLAG((RTX), volatil)) +#define ATTR_PERMANENT_P(RTX) (RTX_FLAG((RTX), return_val)) + +#if 0 +#define strcmp_check(S1, S2) ((S1) == (S2) \ + ? 0 \ + : (gcc_assert (strcmp ((S1), (S2))), 1)) +#else +#define strcmp_check(S1, S2) ((S1) != (S2)) +#endif #include "bconfig.h" #include "system.h" @@ -151,9 +155,7 @@ struct insn_def struct insn_ent { struct insn_ent *next; /* Next in chain. */ - int insn_code; /* Instruction number. */ - int insn_index; /* Index of definition in file */ - int lineno; /* Line number. */ + struct insn_def *def; /* Instruction definition. */ }; /* Each value of an attribute (either constant or computed) is assigned a @@ -179,25 +181,11 @@ struct attr_desc struct attr_value *default_val; /* Default value for this attribute. */ int lineno : 24; /* Line number. */ unsigned is_numeric : 1; /* Values of this attribute are numeric. */ - unsigned negative_ok : 1; /* Allow negative numeric values. */ - unsigned unsigned_p : 1; /* Make the output function unsigned int. */ unsigned is_const : 1; /* Attribute value constant for each run. */ unsigned is_special : 1; /* Don't call `write_attr_set'. */ - unsigned func_units_p : 1; /* This is the function_units attribute. */ - unsigned blockage_p : 1; /* This is the blockage range function. */ unsigned static_p : 1; /* Make the output function static. */ }; -#define NULL_ATTR (struct attr_desc *) NULL - -/* A range of values. */ - -struct range -{ - int min; - int max; -}; - /* Structure for each DEFINE_DELAY. */ struct delay_desc @@ -208,43 +196,6 @@ struct delay_desc int lineno; /* Line number. */ }; -/* Record information about each DEFINE_FUNCTION_UNIT. */ - -struct function_unit_op -{ - rtx condexp; /* Expression TRUE for applicable insn. */ - struct function_unit_op *next; /* Next operation for this function unit. */ - int num; /* Ordinal for this operation type in unit. */ - int ready; /* Cost until data is ready. */ - int issue_delay; /* Cost until unit can accept another insn. */ - rtx conflict_exp; /* Expression TRUE for insns incurring issue delay. */ - rtx issue_exp; /* Expression computing issue delay. */ - int lineno; /* Line number. */ -}; - -/* Record information about each function unit mentioned in a - DEFINE_FUNCTION_UNIT. */ - -struct function_unit -{ - const char *name; /* Function unit name. */ - struct function_unit *next; /* Next function unit. */ - int num; /* Ordinal of this unit type. */ - int multiplicity; /* Number of units of this type. */ - int simultaneity; /* Maximum number of simultaneous insns - on this function unit or 0 if unlimited. */ - rtx condexp; /* Expression TRUE for insn needing unit. */ - int num_opclasses; /* Number of different operation types. */ - struct function_unit_op *ops; /* Pointer to first operation type. */ - int needs_conflict_function; /* Nonzero if a conflict function required. */ - int needs_blockage_function; /* Nonzero if a blockage function required. */ - int needs_range_function; /* Nonzero if blockage range function needed. */ - rtx default_cost; /* Conflict cost, if constant. */ - struct range issue_delay; /* Range of issue delay values. */ - int max_blockage; /* Maximum time an insn blocks the unit. */ - int first_lineno; /* First seen line number. */ -}; - /* Listheads of above structures. */ /* This one is indexed by the first character of the attribute name. */ @@ -252,50 +203,6 @@ struct function_unit static struct attr_desc *attrs[MAX_ATTRS_INDEX]; static struct insn_def *defs; static struct delay_desc *delays; -static struct function_unit *units; - -/* An expression where all the unknown terms are EQ_ATTR tests can be - rearranged into a COND provided we can enumerate all possible - combinations of the unknown values. The set of combinations become the - tests of the COND; the value of the expression given that combination is - computed and becomes the corresponding value. To do this, we must be - able to enumerate all values for each attribute used in the expression - (currently, we give up if we find a numeric attribute). - - If the set of EQ_ATTR tests used in an expression tests the value of N - different attributes, the list of all possible combinations can be made - by walking the N-dimensional attribute space defined by those - attributes. We record each of these as a struct dimension. - - The algorithm relies on sharing EQ_ATTR nodes: if two nodes in an - expression are the same, the will also have the same address. We find - all the EQ_ATTR nodes by marking them ATTR_EQ_ATTR_P. This bit later - represents the value of an EQ_ATTR node, so once all nodes are marked, - they are also given an initial value of FALSE. - - We then separate the set of EQ_ATTR nodes into dimensions for each - attribute and put them on the VALUES list. Terms are added as needed by - `add_values_to_cover' so that all possible values of the attribute are - tested. - - Each dimension also has a current value. This is the node that is - currently considered to be TRUE. If this is one of the nodes added by - `add_values_to_cover', all the EQ_ATTR tests in the original expression - will be FALSE. Otherwise, only the CURRENT_VALUE will be true. - - NUM_VALUES is simply the length of the VALUES list and is there for - convenience. - - Once the dimensions are created, the algorithm enumerates all possible - values and computes the current value of the given expression. */ - -struct dimension -{ - struct attr_desc *attr; /* Attribute for this dimension. */ - rtx values; /* List of attribute values used. */ - rtx current_value; /* Position in the list for the TRUE value. */ - int num_values; /* Length of the values list. */ -}; /* Other variables. */ @@ -308,15 +215,10 @@ static int address_used; static int length_used; static int num_delays; static int have_annul_true, have_annul_false; -static int num_units, num_unit_opclasses; static int num_insn_ents; int num_dfa_decls; -/* Used as operand to `operate_exp': */ - -enum operator {PLUS_OP, MINUS_OP, POS_MINUS_OP, EQ_OP, OR_OP, ORX_OP, MAX_OP, MIN_OP, RANGE_OP}; - /* Stores, for each insn code, the number of constraint alternatives. */ static int *insn_n_alternatives; @@ -339,6 +241,10 @@ static rtx true_rtx, false_rtx; /* Used to reduce calls to `strcmp' */ static char *alternative_name; +static const char *length_str; +static const char *delay_type_str; +static const char *delay_1_0_str; +static const char *num_delay_slots_str; /* Indicate that REG_DEAD notes are valid if dead_or_set_p is ever called. */ @@ -365,6 +271,8 @@ int optimize = 0; (EXP) = (XSTR ((EXP), 1) == current_alternative_string \ ? true_rtx : false_rtx); +#define DEF_ATTR_STRING(S) (attr_string ((S), strlen (S))) + /* These are referenced by rtlanal.c and hence need to be defined somewhere. They won't actually be used. */ @@ -385,10 +293,6 @@ static struct attr_value *get_attr_value (rtx, struct attr_desc *, int); static rtx copy_rtx_unchanging (rtx); static rtx copy_boolean (rtx); static void expand_delays (void); -static rtx operate_exp (enum operator, rtx, rtx); -static void expand_units (void); -static rtx simplify_knowing (rtx, rtx); -static rtx encode_units_mask (rtx); static void fill_attr (struct attr_desc *); static rtx substitute_address (rtx, rtx (*) (rtx), rtx (*) (rtx)); static void make_length_attrs (void); @@ -398,16 +302,7 @@ static rtx one_fn (rtx); static rtx max_fn (rtx); static void write_length_unit_log (void); static rtx simplify_cond (rtx, int, int); -static rtx simplify_by_exploding (rtx); -static int find_and_mark_used_attributes (rtx, rtx *, int *); -static void unmark_used_attributes (rtx, struct dimension *, int); -static int add_values_to_cover (struct dimension *); -static int increment_current_value (struct dimension *, int); -static rtx test_for_current_value (struct dimension *, int); -static rtx simplify_with_current_value (rtx, struct dimension *, int); -static rtx simplify_with_current_value_aux (rtx); static void clear_struct_flag (rtx); -static int count_sub_rtxs (rtx, int); static void remove_insn_ent (struct attr_value *, struct insn_ent *); static void insert_insn_ent (struct attr_value *, struct insn_ent *); static rtx insert_right_side (enum rtx_code, rtx, rtx, int, int); @@ -425,7 +320,6 @@ static int compares_alternatives_p (rtx); static int contained_in_p (rtx, rtx); static void gen_insn (rtx, int); static void gen_delay (rtx, int); -static void gen_unit (rtx, int); static void write_test_expr (rtx, int); static int max_attr_value (rtx, int*); static int or_attr_value (rtx, int*); @@ -435,30 +329,31 @@ static rtx eliminate_known_true (rtx, rtx, int, int); static void write_attr_set (struct attr_desc *, int, rtx, const char *, const char *, rtx, int, int); +static void write_insn_cases (struct insn_ent *, int); static void write_attr_case (struct attr_desc *, struct attr_value *, int, const char *, const char *, int, rtx); -static void write_unit_name (const char *, int, const char *); static void write_attr_valueq (struct attr_desc *, const char *); static void write_attr_value (struct attr_desc *, rtx); static void write_upcase (const char *); static void write_indent (int); static void write_eligible_delay (const char *); -static void write_function_unit_info (void); -static void write_complex_function (struct function_unit *, const char *, - const char *); static int write_expr_attr_cache (rtx, struct attr_desc *); -static void write_toplevel_expr (rtx); static void write_const_num_delay_slots (void); static char *next_comma_elt (const char **); -static struct attr_desc *find_attr (const char *, int); +static struct attr_desc *find_attr (const char **, int); static struct attr_value *find_most_used (struct attr_desc *); -static rtx find_single_value (struct attr_desc *); -static void extend_range (struct range *, int, int); static rtx attr_eq (const char *, const char *); static const char *attr_numeral (int); static int attr_equal_p (rtx, rtx); static rtx attr_copy_rtx (rtx); static int attr_rtx_cost (rtx); +static bool attr_alt_subset_p (rtx, rtx); +static bool attr_alt_subset_of_compl_p (rtx, rtx); +static rtx attr_alt_intersection (rtx, rtx); +static rtx attr_alt_union (rtx, rtx); +static rtx attr_alt_complement (rtx); +static bool attr_alt_bit_p (rtx, int); +static rtx mk_attr_alt (int); #define oballoc(size) obstack_alloc (hash_obstack, size) @@ -527,7 +422,7 @@ attr_hash_add_string (int hashcode, char *str) In some cases we cannot uniquify; then we return an ordinary impermanent rtx with ATTR_PERMANENT_P clear. - Args are like gen_rtx, but without the mode: + Args are as follows: rtx attr_rtx (code, [element1, ..., elementn]) */ @@ -543,7 +438,7 @@ attr_rtx_1 (enum rtx_code code, va_list p) Use that entry if one is found; otherwise create a new RTL and add it to the table. */ - if (GET_RTX_CLASS (code) == '1') + if (GET_RTX_CLASS (code) == RTX_UNARY) { rtx arg0 = va_arg (p, rtx); @@ -569,9 +464,10 @@ attr_rtx_1 (enum rtx_code code, va_list p) XEXP (rt_val, 0) = arg0; } } - else if (GET_RTX_CLASS (code) == 'c' - || GET_RTX_CLASS (code) == '2' - || GET_RTX_CLASS (code) == '<') + else if (GET_RTX_CLASS (code) == RTX_BIN_ARITH + || GET_RTX_CLASS (code) == RTX_COMM_ARITH + || GET_RTX_CLASS (code) == RTX_COMPARE + || GET_RTX_CLASS (code) == RTX_COMM_COMPARE) { rtx arg0 = va_arg (p, rtx); rtx arg1 = va_arg (p, rtx); @@ -606,8 +502,7 @@ attr_rtx_1 (enum rtx_code code, va_list p) { char *arg0 = va_arg (p, char *); - if (code == SYMBOL_REF) - arg0 = attr_string (arg0, strlen (arg0)); + arg0 = DEF_ATTR_STRING (arg0); hashcode = ((HOST_WIDE_INT) code + RTL_HASH (arg0)); for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next) @@ -693,7 +588,7 @@ attr_rtx_1 (enum rtx_code code, va_list p) break; default: - abort (); + gcc_unreachable (); } } return rt_val; @@ -730,20 +625,18 @@ attr_printf (unsigned int len, const char *fmt, ...) va_start (p, fmt); - if (len > sizeof str - 1) /* Leave room for \0. */ - abort (); + gcc_assert (len < sizeof str); /* Leave room for \0. */ vsprintf (str, fmt, p); va_end (p); - return attr_string (str, strlen (str)); + return DEF_ATTR_STRING (str); } static rtx attr_eq (const char *name, const char *value) { - return attr_rtx (EQ_ATTR, attr_string (name, strlen (name)), - attr_string (value, strlen (value))); + return attr_rtx (EQ_ATTR, DEF_ATTR_STRING (name), DEF_ATTR_STRING (value)); } static const char * @@ -817,7 +710,6 @@ attr_copy_rtx (rtx orig) switch (code) { case REG: - case QUEUED: case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -836,7 +728,6 @@ attr_copy_rtx (rtx orig) ATTR_IND_SIMPLIFIED_P (copy) = ATTR_IND_SIMPLIFIED_P (orig); ATTR_CURR_SIMPLIFIED_P (copy) = ATTR_CURR_SIMPLIFIED_P (orig); ATTR_PERMANENT_P (copy) = ATTR_PERMANENT_P (orig); - ATTR_EQ_ATTR_P (copy) = ATTR_EQ_ATTR_P (orig); format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); @@ -876,7 +767,7 @@ attr_copy_rtx (rtx orig) break; default: - abort (); + gcc_unreachable (); } } return copy; @@ -916,16 +807,11 @@ check_attr_test (rtx exp, int is_const, int lineno) else if (n_comma_elts (XSTR (exp, 1)) == 1) { - attr = find_attr (XSTR (exp, 0), 0); + attr = find_attr (&XSTR (exp, 0), 0); if (attr == NULL) { if (! strcmp (XSTR (exp, 0), "alternative")) - { - XSTR (exp, 0) = alternative_name; - /* This can't be simplified any further. */ - ATTR_IND_SIMPLIFIED_P (exp) = 1; - return exp; - } + return mk_attr_alt (1 << atoi (XSTR (exp, 1))); else fatal ("unknown attribute `%s' in EQ_ATTR", XSTR (exp, 0)); } @@ -965,16 +851,29 @@ check_attr_test (rtx exp, int is_const, int lineno) } else { - /* Make an IOR tree of the possible values. */ - orexp = false_rtx; - name_ptr = XSTR (exp, 1); - while ((p = next_comma_elt (&name_ptr)) != NULL) + if (! strcmp (XSTR (exp, 0), "alternative")) { - newexp = attr_eq (XSTR (exp, 0), p); - orexp = insert_right_side (IOR, orexp, newexp, -2, -2); + int set = 0; + + name_ptr = XSTR (exp, 1); + while ((p = next_comma_elt (&name_ptr)) != NULL) + set |= 1 << atoi (p); + + return mk_attr_alt (set); } + else + { + /* Make an IOR tree of the possible values. */ + orexp = false_rtx; + name_ptr = XSTR (exp, 1); + while ((p = next_comma_elt (&name_ptr)) != NULL) + { + newexp = attr_eq (XSTR (exp, 0), p); + orexp = insert_right_side (IOR, orexp, newexp, -2, -2); + } - return check_attr_test (orexp, is_const, lineno); + return check_attr_test (orexp, is_const, lineno); + } } break; @@ -998,7 +897,6 @@ check_attr_test (rtx exp, int is_const, int lineno) XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const, lineno); break; - case MATCH_INSN: case MATCH_OPERAND: if (is_const) fatal ("RTL operator \"%s\" not valid in constant attribute test", @@ -1061,7 +959,7 @@ check_attr_value (rtx exp, struct attr_desc *attr) break; } - if (INTVAL (exp) < 0 && ! attr->negative_ok) + if (INTVAL (exp) < 0) { message_with_line (attr->lineno, "negative numeric value specified for attribute %s", @@ -1078,8 +976,6 @@ check_attr_value (rtx exp, struct attr_desc *attr) if (attr == 0 || attr->is_numeric) { p = XSTR (exp, 0); - if (attr && attr->negative_ok && *p == '-') - p++; for (; *p; p++) if (! ISDIGIT (*p)) { @@ -1127,7 +1023,7 @@ check_attr_value (rtx exp, struct attr_desc *attr) have_error = 1; break; } - /* FALLTHRU */ + /* Fall through. */ case IOR: case AND: @@ -1166,7 +1062,7 @@ check_attr_value (rtx exp, struct attr_desc *attr) case ATTR: { - struct attr_desc *attr2 = find_attr (XSTR (exp, 0), 0); + struct attr_desc *attr2 = find_attr (&XSTR (exp, 0), 0); if (attr2 == NULL) { message_with_line (attr ? attr->lineno : 0, @@ -1182,8 +1078,7 @@ check_attr_value (rtx exp, struct attr_desc *attr) have_error = 1; } else if (attr - && (attr->is_numeric != attr2->is_numeric - || (! attr->negative_ok && attr2->negative_ok))) + && attr->is_numeric != attr2->is_numeric) { message_with_line (attr->lineno, "numeric attribute mismatch calling `%s' from `%s'", @@ -1326,7 +1221,7 @@ check_defs (void) if (value == NULL_RTX) continue; - if ((attr = find_attr (XSTR (XEXP (value, 0), 0), 0)) == NULL) + if ((attr = find_attr (&XSTR (XEXP (value, 0), 0), 0)) == NULL) { message_with_line (id->lineno, "unknown attribute %s", XSTR (XEXP (value, 0), 0)); @@ -1364,6 +1259,8 @@ make_canonical (struct attr_desc *attr, rtx exp) fatal ("(attr_value \"*\") used in invalid context"); exp = attr->default_val->value; } + else + XSTR (exp, 0) = DEF_ATTR_STRING (XSTR (exp, 0)); break; @@ -1424,6 +1321,17 @@ copy_boolean (rtx exp) if (GET_CODE (exp) == AND || GET_CODE (exp) == IOR) return attr_rtx (GET_CODE (exp), copy_boolean (XEXP (exp, 0)), copy_boolean (XEXP (exp, 1))); + if (GET_CODE (exp) == MATCH_OPERAND) + { + XSTR (exp, 1) = DEF_ATTR_STRING (XSTR (exp, 1)); + XSTR (exp, 2) = DEF_ATTR_STRING (XSTR (exp, 2)); + } + else if (GET_CODE (exp) == EQ_ATTR) + { + XSTR (exp, 0) = DEF_ATTR_STRING (XSTR (exp, 0)); + XSTR (exp, 1) = DEF_ATTR_STRING (XSTR (exp, 1)); + } + return exp; } @@ -1454,7 +1362,7 @@ get_attr_value (rtx value, struct attr_desc *attr, int insn_code) for (av = attr->first_value; av; av = av->next) if (rtx_equal_p (value, av->value) && (num_alt == 0 || av->first_insn == NULL - || insn_alternatives[av->first_insn->insn_code])) + || insn_alternatives[av->first_insn->def->insn_code])) return av; av = oballoc (sizeof (struct attr_value)); @@ -1504,7 +1412,7 @@ expand_delays (void) = make_numeric_value (XVECLEN (delay->def, 1) / 3); } - make_internal_attr ("*num_delay_slots", condexp, ATTR_NONE); + make_internal_attr (num_delay_slots_str, condexp, ATTR_NONE); /* If more than one delay type, do the same for computing the delay type. */ if (num_delays > 1) @@ -1519,7 +1427,7 @@ expand_delays (void) XVECEXP (condexp, 0, i + 1) = make_numeric_value (delay->num); } - make_internal_attr ("*delay_type", condexp, ATTR_SPECIAL); + make_internal_attr (delay_type_str, condexp, ATTR_SPECIAL); } /* For each delay possibility and delay slot, compute an eligibility @@ -1566,1291 +1474,779 @@ expand_delays (void) } } -/* This function is given a left and right side expression and an operator. - Each side is a conditional expression, each alternative of which has a - numerical value. The function returns another conditional expression - which, for every possible set of condition values, returns a value that is - the operator applied to the values of the two sides. - - Since this is called early, it must also support IF_THEN_ELSE. */ +/* Once all attributes and insns have been read and checked, we construct for + each attribute value a list of all the insns that have that value for + the attribute. */ -static rtx -operate_exp (enum operator op, rtx left, rtx right) +static void +fill_attr (struct attr_desc *attr) { - int left_value, right_value; - rtx newexp; + struct attr_value *av; + struct insn_ent *ie; + struct insn_def *id; int i; + rtx value; - /* If left is a string, apply operator to it and the right side. */ - if (GET_CODE (left) == CONST_STRING) - { - /* If right is also a string, just perform the operation. */ - if (GET_CODE (right) == CONST_STRING) - { - left_value = atoi (XSTR (left, 0)); - right_value = atoi (XSTR (right, 0)); - switch (op) - { - case PLUS_OP: - i = left_value + right_value; - break; - - case MINUS_OP: - i = left_value - right_value; - break; - - case POS_MINUS_OP: /* The positive part of LEFT - RIGHT. */ - if (left_value > right_value) - i = left_value - right_value; - else - i = 0; - break; - - case OR_OP: - case ORX_OP: - i = left_value | right_value; - break; - - case EQ_OP: - i = left_value == right_value; - break; - - case RANGE_OP: - i = (left_value << (HOST_BITS_PER_INT / 2)) | right_value; - break; - - case MAX_OP: - if (left_value > right_value) - i = left_value; - else - i = right_value; - break; - - case MIN_OP: - if (left_value < right_value) - i = left_value; - else - i = right_value; - break; - - default: - abort (); - } + /* Don't fill constant attributes. The value is independent of + any particular insn. */ + if (attr->is_const) + return; - if (i == left_value) - return left; - if (i == right_value) - return right; - return make_numeric_value (i); - } - else if (GET_CODE (right) == IF_THEN_ELSE) - { - /* Apply recursively to all values within. */ - rtx newleft = operate_exp (op, left, XEXP (right, 1)); - rtx newright = operate_exp (op, left, XEXP (right, 2)); - if (rtx_equal_p (newleft, newright)) - return newleft; - return attr_rtx (IF_THEN_ELSE, XEXP (right, 0), newleft, newright); - } - else if (GET_CODE (right) == COND) - { - int allsame = 1; - rtx defval; + for (id = defs; id; id = id->next) + { + /* If no value is specified for this insn for this attribute, use the + default. */ + value = NULL; + if (XVEC (id->def, id->vec_idx)) + for (i = 0; i < XVECLEN (id->def, id->vec_idx); i++) + if (! strcmp_check (XSTR (XEXP (XVECEXP (id->def, id->vec_idx, i), 0), 0), + attr->name)) + value = XEXP (XVECEXP (id->def, id->vec_idx, i), 1); - newexp = rtx_alloc (COND); - XVEC (newexp, 0) = rtvec_alloc (XVECLEN (right, 0)); - defval = XEXP (newexp, 1) = operate_exp (op, left, XEXP (right, 1)); + if (value == NULL) + av = attr->default_val; + else + av = get_attr_value (value, attr, id->insn_code); - for (i = 0; i < XVECLEN (right, 0); i += 2) - { - XVECEXP (newexp, 0, i) = XVECEXP (right, 0, i); - XVECEXP (newexp, 0, i + 1) - = operate_exp (op, left, XVECEXP (right, 0, i + 1)); - if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1), - defval)) - allsame = 0; - } + ie = oballoc (sizeof (struct insn_ent)); + ie->def = id; + insert_insn_ent (av, ie); + } +} - /* If the resulting cond is trivial (all alternatives - give the same value), optimize it away. */ - if (allsame) - return operate_exp (op, left, XEXP (right, 1)); +/* Given an expression EXP, see if it is a COND or IF_THEN_ELSE that has a + test that checks relative positions of insns (uses MATCH_DUP or PC). + If so, replace it with what is obtained by passing the expression to + ADDRESS_FN. If not but it is a COND or IF_THEN_ELSE, call this routine + recursively on each value (including the default value). Otherwise, + return the value returned by NO_ADDRESS_FN applied to EXP. */ - return newexp; - } - else - fatal ("badly formed attribute value"); - } +static rtx +substitute_address (rtx exp, rtx (*no_address_fn) (rtx), + rtx (*address_fn) (rtx)) +{ + int i; + rtx newexp; - /* A hack to prevent expand_units from completely blowing up: ORX_OP does - not associate through IF_THEN_ELSE. */ - else if (op == ORX_OP && GET_CODE (right) == IF_THEN_ELSE) + if (GET_CODE (exp) == COND) { - return attr_rtx (IOR, left, right); - } + /* See if any tests use addresses. */ + address_used = 0; + for (i = 0; i < XVECLEN (exp, 0); i += 2) + walk_attr_value (XVECEXP (exp, 0, i)); - /* Otherwise, do recursion the other way. */ - else if (GET_CODE (left) == IF_THEN_ELSE) - { - rtx newleft = operate_exp (op, XEXP (left, 1), right); - rtx newright = operate_exp (op, XEXP (left, 2), right); - if (rtx_equal_p (newleft, newright)) - return newleft; - return attr_rtx (IF_THEN_ELSE, XEXP (left, 0), newleft, newright); - } - else if (GET_CODE (left) == COND) - { - int allsame = 1; - rtx defval; + if (address_used) + return (*address_fn) (exp); + /* Make a new copy of this COND, replacing each element. */ newexp = rtx_alloc (COND); - XVEC (newexp, 0) = rtvec_alloc (XVECLEN (left, 0)); - defval = XEXP (newexp, 1) = operate_exp (op, XEXP (left, 1), right); - - for (i = 0; i < XVECLEN (left, 0); i += 2) + XVEC (newexp, 0) = rtvec_alloc (XVECLEN (exp, 0)); + for (i = 0; i < XVECLEN (exp, 0); i += 2) { - XVECEXP (newexp, 0, i) = XVECEXP (left, 0, i); + XVECEXP (newexp, 0, i) = XVECEXP (exp, 0, i); XVECEXP (newexp, 0, i + 1) - = operate_exp (op, XVECEXP (left, 0, i + 1), right); - if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1), - defval)) - allsame = 0; + = substitute_address (XVECEXP (exp, 0, i + 1), + no_address_fn, address_fn); } - /* If the cond is trivial (all alternatives give the same value), - optimize it away. */ - if (allsame) - return operate_exp (op, XEXP (left, 1), right); - - /* If the result is the same as the LEFT operand, - just use that. */ - if (rtx_equal_p (newexp, left)) - return left; + XEXP (newexp, 1) = substitute_address (XEXP (exp, 1), + no_address_fn, address_fn); return newexp; } - else - fatal ("badly formed attribute value"); - /* NOTREACHED */ - return NULL; -} - -/* Once all attributes and DEFINE_FUNCTION_UNITs have been read, we - construct a number of attributes. - - The first produces a function `function_units_used' which is given an - insn and produces an encoding showing which function units are required - for the execution of that insn. If the value is non-negative, the insn - uses that unit; otherwise, the value is a one's complement mask of units - used. - - The second produces a function `result_ready_cost' which is used to - determine the time that the result of an insn will be ready and hence - a worst-case schedule. - - Both of these produce quite complex expressions which are then set as the - default value of internal attributes. Normal attribute simplification - should produce reasonable expressions. - - For each unit, a `_unit_ready_cost' function will take an - insn and give the delay until that unit will be ready with the result - and a `_unit_conflict_cost' function is given an insn already - executing on the unit and a candidate to execute and will give the - cost from the time the executing insn started until the candidate - can start (ignore limitations on the number of simultaneous insns). - - For each unit, a `_unit_blockage' function is given an insn - already executing on the unit and a candidate to execute and will - give the delay incurred due to function unit conflicts. The range of - blockage cost values for a given executing insn is given by the - `_unit_blockage_range' function. These values are encoded in - an int where the upper half gives the minimum value and the lower - half gives the maximum value. */ - -static void -expand_units (void) -{ - struct function_unit *unit, **unit_num; - struct function_unit_op *op, **op_array, ***unit_ops; - rtx unitsmask; - rtx readycost; - rtx newexp; - const char *str; - int i, j, u, num, nvalues; - - /* Rebuild the condition for the unit to share the RTL expressions. - Sharing is required by simplify_by_exploding. Build the issue delay - expressions. Validate the expressions we were given for the conditions - and conflict vector. Then make attributes for use in the conflict - function. */ - - for (unit = units; unit; unit = unit->next) + else if (GET_CODE (exp) == IF_THEN_ELSE) { - unit->condexp = check_attr_test (unit->condexp, 0, unit->first_lineno); - - for (op = unit->ops; op; op = op->next) - { - rtx issue_delay = make_numeric_value (op->issue_delay); - rtx issue_exp = issue_delay; - - /* Build, validate, and simplify the issue delay expression. */ - if (op->conflict_exp != true_rtx) - issue_exp = attr_rtx (IF_THEN_ELSE, op->conflict_exp, - issue_exp, make_numeric_value (0)); - issue_exp = check_attr_value (make_canonical (NULL_ATTR, - issue_exp), - NULL_ATTR); - issue_exp = simplify_knowing (issue_exp, unit->condexp); - op->issue_exp = issue_exp; - - /* Make an attribute for use in the conflict function if needed. */ - unit->needs_conflict_function = (unit->issue_delay.min - != unit->issue_delay.max); - if (unit->needs_conflict_function) - { - str = attr_printf ((strlen (unit->name) + sizeof "*_cost_" - + MAX_DIGITS), - "*%s_cost_%d", unit->name, op->num); - make_internal_attr (str, issue_exp, ATTR_SPECIAL); - } + address_used = 0; + walk_attr_value (XEXP (exp, 0)); + if (address_used) + return (*address_fn) (exp); - /* Validate the condition. */ - op->condexp = check_attr_test (op->condexp, 0, op->lineno); - } + return attr_rtx (IF_THEN_ELSE, + substitute_address (XEXP (exp, 0), + no_address_fn, address_fn), + substitute_address (XEXP (exp, 1), + no_address_fn, address_fn), + substitute_address (XEXP (exp, 2), + no_address_fn, address_fn)); } - /* Compute the mask of function units used. Initially, the unitsmask is - zero. Set up a conditional to compute each unit's contribution. */ - unitsmask = make_numeric_value (0); - newexp = rtx_alloc (IF_THEN_ELSE); - XEXP (newexp, 2) = make_numeric_value (0); + return (*no_address_fn) (exp); +} - /* If we have just a few units, we may be all right expanding the whole - thing. But the expansion is 2**N in space on the number of opclasses, - so we can't do this for very long -- Alpha and MIPS in particular have - problems with this. So in that situation, we fall back on an alternate - implementation method. */ -#define NUM_UNITOP_CUTOFF 20 +/* Make new attributes from the `length' attribute. The following are made, + each corresponding to a function called from `shorten_branches' or + `get_attr_length': - if (num_unit_opclasses < NUM_UNITOP_CUTOFF) - { - /* Merge each function unit into the unit mask attributes. */ - for (unit = units; unit; unit = unit->next) - { - XEXP (newexp, 0) = unit->condexp; - XEXP (newexp, 1) = make_numeric_value (1 << unit->num); - unitsmask = operate_exp (OR_OP, unitsmask, newexp); - } - } - else - { - /* Merge each function unit into the unit mask attributes. */ - for (unit = units; unit; unit = unit->next) - { - XEXP (newexp, 0) = unit->condexp; - XEXP (newexp, 1) = make_numeric_value (1 << unit->num); - unitsmask = operate_exp (ORX_OP, unitsmask, attr_copy_rtx (newexp)); - } - } + *insn_default_length This is the length of the insn to be returned + by `get_attr_length' before `shorten_branches' + has been called. In each case where the length + depends on relative addresses, the largest + possible is used. This routine is also used + to compute the initial size of the insn. - /* Simplify the unit mask expression, encode it, and make an attribute - for the function_units_used function. */ - unitsmask = simplify_by_exploding (unitsmask); + *insn_variable_length_p This returns 1 if the insn's length depends + on relative addresses, zero otherwise. - if (num_unit_opclasses < NUM_UNITOP_CUTOFF) - unitsmask = encode_units_mask (unitsmask); - else + *insn_current_length This is only called when it is known that the + insn has a variable length and returns the + current length, based on relative addresses. + */ + +static void +make_length_attrs (void) +{ + static const char *new_names[] = { - /* We can no longer encode unitsmask at compile time, so emit code to - calculate it at runtime. Rather, put a marker for where we'd do - the code, and actually output it in write_attr_get(). */ - unitsmask = attr_rtx (FFS, unitsmask); - } + "*insn_default_length", + "*insn_variable_length_p", + "*insn_current_length" + }; + static rtx (*const no_address_fn[]) (rtx) = {identity_fn, zero_fn, zero_fn}; + static rtx (*const address_fn[]) (rtx) = {max_fn, one_fn, identity_fn}; + size_t i; + struct attr_desc *length_attr, *new_attr; + struct attr_value *av, *new_av; + struct insn_ent *ie, *new_ie; - make_internal_attr ("*function_units_used", unitsmask, - (ATTR_NEGATIVE_OK | ATTR_FUNC_UNITS)); + /* See if length attribute is defined. If so, it must be numeric. Make + it special so we don't output anything for it. */ + length_attr = find_attr (&length_str, 0); + if (length_attr == 0) + return; - /* Create an array of ops for each unit. Add an extra unit for the - result_ready_cost function that has the ops of all other units. */ - unit_ops = xmalloc ((num_units + 1) * sizeof (struct function_unit_op **)); - unit_num = xmalloc ((num_units + 1) * sizeof (struct function_unit *)); + if (! length_attr->is_numeric) + fatal ("length attribute must be numeric"); - unit_num[num_units] = unit = xmalloc (sizeof (struct function_unit)); - unit->num = num_units; - unit->num_opclasses = 0; + length_attr->is_const = 0; + length_attr->is_special = 1; - for (unit = units; unit; unit = unit->next) + /* Make each new attribute, in turn. */ + for (i = 0; i < ARRAY_SIZE (new_names); i++) { - unit_num[num_units]->num_opclasses += unit->num_opclasses; - unit_num[unit->num] = unit; - unit_ops[unit->num] = op_array = - xmalloc (unit->num_opclasses * sizeof (struct function_unit_op *)); - - for (op = unit->ops; op; op = op->next) - op_array[op->num] = op; + make_internal_attr (new_names[i], + substitute_address (length_attr->default_val->value, + no_address_fn[i], address_fn[i]), + ATTR_NONE); + new_attr = find_attr (&new_names[i], 0); + for (av = length_attr->first_value; av; av = av->next) + for (ie = av->first_insn; ie; ie = ie->next) + { + new_av = get_attr_value (substitute_address (av->value, + no_address_fn[i], + address_fn[i]), + new_attr, ie->def->insn_code); + new_ie = oballoc (sizeof (struct insn_ent)); + new_ie->def = ie->def; + insert_insn_ent (new_av, new_ie); + } } +} - /* Compose the array of ops for the extra unit. */ - unit_ops[num_units] = op_array = - xmalloc (unit_num[num_units]->num_opclasses - * sizeof (struct function_unit_op *)); +/* Utility functions called from above routine. */ - for (unit = units, i = 0; unit; i += unit->num_opclasses, unit = unit->next) - memcpy (&op_array[i], unit_ops[unit->num], - unit->num_opclasses * sizeof (struct function_unit_op *)); +static rtx +identity_fn (rtx exp) +{ + return exp; +} - /* Compute the ready cost function for each unit by computing the - condition for each non-default value. */ - for (u = 0; u <= num_units; u++) - { - rtx orexp; - int value; +static rtx +zero_fn (rtx exp ATTRIBUTE_UNUSED) +{ + return make_numeric_value (0); +} - unit = unit_num[u]; - op_array = unit_ops[unit->num]; - num = unit->num_opclasses; +static rtx +one_fn (rtx exp ATTRIBUTE_UNUSED) +{ + return make_numeric_value (1); +} - /* Sort the array of ops into increasing ready cost order. */ - for (i = 0; i < num; i++) - for (j = num - 1; j > i; j--) - if (op_array[j - 1]->ready < op_array[j]->ready) - { - op = op_array[j]; - op_array[j] = op_array[j - 1]; - op_array[j - 1] = op; - } +static rtx +max_fn (rtx exp) +{ + int unknown; + return make_numeric_value (max_attr_value (exp, &unknown)); +} - /* Determine how many distinct non-default ready cost values there - are. We use a default ready cost value of 1. */ - nvalues = 0; value = 1; - for (i = num - 1; i >= 0; i--) - if (op_array[i]->ready > value) - { - value = op_array[i]->ready; - nvalues++; - } - - if (nvalues == 0) - readycost = make_numeric_value (1); - else - { - /* Construct the ready cost expression as a COND of each value from - the largest to the smallest. */ - readycost = rtx_alloc (COND); - XVEC (readycost, 0) = rtvec_alloc (nvalues * 2); - XEXP (readycost, 1) = make_numeric_value (1); - - nvalues = 0; - orexp = false_rtx; - value = op_array[0]->ready; - for (i = 0; i < num; i++) - { - op = op_array[i]; - if (op->ready <= 1) - break; - else if (op->ready == value) - orexp = insert_right_side (IOR, orexp, op->condexp, -2, -2); - else - { - XVECEXP (readycost, 0, nvalues * 2) = orexp; - XVECEXP (readycost, 0, nvalues * 2 + 1) - = make_numeric_value (value); - nvalues++; - value = op->ready; - orexp = op->condexp; - } - } - XVECEXP (readycost, 0, nvalues * 2) = orexp; - XVECEXP (readycost, 0, nvalues * 2 + 1) = make_numeric_value (value); - } +static void +write_length_unit_log (void) +{ + struct attr_desc *length_attr = find_attr (&length_str, 0); + struct attr_value *av; + struct insn_ent *ie; + unsigned int length_unit_log, length_or; + int unknown = 0; - if (u < num_units) - { - rtx max_blockage = 0, min_blockage = 0; + if (length_attr == 0) + return; + length_or = or_attr_value (length_attr->default_val->value, &unknown); + for (av = length_attr->first_value; av; av = av->next) + for (ie = av->first_insn; ie; ie = ie->next) + length_or |= or_attr_value (av->value, &unknown); - /* Simplify the readycost expression by only considering insns - that use the unit. */ - readycost = simplify_knowing (readycost, unit->condexp); + if (unknown) + length_unit_log = 0; + else + { + length_or = ~length_or; + for (length_unit_log = 0; length_or & 1; length_or >>= 1) + length_unit_log++; + } + printf ("int length_unit_log = %u;\n", length_unit_log); +} - /* Determine the blockage cost the executing insn (E) given - the candidate insn (C). This is the maximum of the issue - delay, the pipeline delay, and the simultaneity constraint. - Each function_unit_op represents the characteristics of the - candidate insn, so in the expressions below, C is a known - term and E is an unknown term. +/* Take a COND expression and see if any of the conditions in it can be + simplified. If any are known true or known false for the particular insn + code, the COND can be further simplified. - We compute the blockage cost for each E for every possible C. - Thus OP represents E, and READYCOST is a list of values for - every possible C. + Also call ourselves on any COND operations that are values of this COND. - The issue delay function for C is op->issue_exp and is used to - write the `_unit_conflict_cost' function. Symbolically - this is "ISSUE-DELAY (E,C)". + We do not modify EXP; rather, we make and return a new rtx. */ - The pipeline delay results form the FIFO constraint on the - function unit and is "READY-COST (E) + 1 - READY-COST (C)". +static rtx +simplify_cond (rtx exp, int insn_code, int insn_index) +{ + int i, j; + /* We store the desired contents here, + then build a new expression if they don't match EXP. */ + rtx defval = XEXP (exp, 1); + rtx new_defval = XEXP (exp, 1); + int len = XVECLEN (exp, 0); + rtx *tests = xmalloc (len * sizeof (rtx)); + int allsame = 1; + rtx ret; - The simultaneity constraint is based on how long it takes to - fill the unit given the minimum issue delay. FILL-TIME is the - constant "MIN (ISSUE-DELAY (*,*)) * (SIMULTANEITY - 1)", and - the simultaneity constraint is "READY-COST (E) - FILL-TIME" - if SIMULTANEITY is nonzero and zero otherwise. + /* This lets us free all storage allocated below, if appropriate. */ + obstack_finish (rtl_obstack); - Thus, BLOCKAGE (E,C) when SIMULTANEITY is zero is + memcpy (tests, XVEC (exp, 0)->elem, len * sizeof (rtx)); - MAX (ISSUE-DELAY (E,C), - READY-COST (E) - (READY-COST (C) - 1)) + /* See if default value needs simplification. */ + if (GET_CODE (defval) == COND) + new_defval = simplify_cond (defval, insn_code, insn_index); - and otherwise + /* Simplify the subexpressions, and see what tests we can get rid of. */ - MAX (ISSUE-DELAY (E,C), - READY-COST (E) - (READY-COST (C) - 1), - READY-COST (E) - FILL-TIME) + for (i = 0; i < len; i += 2) + { + rtx newtest, newval; - The `_unit_blockage' function is computed by determining - this value for each candidate insn. As these values are - computed, we also compute the upper and lower bounds for - BLOCKAGE (E,*). These are combined to form the function - `_unit_blockage_range'. Finally, the maximum blockage - cost, MAX (BLOCKAGE (*,*)), is computed. */ + /* Simplify this test. */ + newtest = simplify_test_exp_in_temp (tests[i], insn_code, insn_index); + tests[i] = newtest; - for (op = unit->ops; op; op = op->next) - { - rtx blockage = op->issue_exp; - blockage = simplify_knowing (blockage, unit->condexp); + newval = tests[i + 1]; + /* See if this value may need simplification. */ + if (GET_CODE (newval) == COND) + newval = simplify_cond (newval, insn_code, insn_index); - /* Add this op's contribution to MAX (BLOCKAGE (E,*)) and - MIN (BLOCKAGE (E,*)). */ - if (max_blockage == 0) - max_blockage = min_blockage = blockage; - else - { - max_blockage - = simplify_knowing (operate_exp (MAX_OP, max_blockage, - blockage), - unit->condexp); - min_blockage - = simplify_knowing (operate_exp (MIN_OP, min_blockage, - blockage), - unit->condexp); - } + /* Look for ways to delete or combine this test. */ + if (newtest == true_rtx) + { + /* If test is true, make this value the default + and discard this + any following tests. */ + len = i; + defval = tests[i + 1]; + new_defval = newval; + } - /* Make an attribute for use in the blockage function. */ - str = attr_printf ((strlen (unit->name) + sizeof "*_block_" - + MAX_DIGITS), - "*%s_block_%d", unit->name, op->num); - make_internal_attr (str, blockage, ATTR_SPECIAL); - } + else if (newtest == false_rtx) + { + /* If test is false, discard it and its value. */ + for (j = i; j < len - 2; j++) + tests[j] = tests[j + 2]; + i -= 2; + len -= 2; + } - /* Record MAX (BLOCKAGE (*,*)). */ - { - int unknown; - unit->max_blockage = max_attr_value (max_blockage, &unknown); - } + else if (i > 0 && attr_equal_p (newval, tests[i - 1])) + { + /* If this value and the value for the prev test are the same, + merge the tests. */ - /* See if the upper and lower bounds of BLOCKAGE (E,*) are the - same. If so, the blockage function carries no additional - information and is not written. */ - newexp = operate_exp (EQ_OP, max_blockage, min_blockage); - newexp = simplify_knowing (newexp, unit->condexp); - unit->needs_blockage_function - = (GET_CODE (newexp) != CONST_STRING - || atoi (XSTR (newexp, 0)) != 1); - - /* If the all values of BLOCKAGE (E,C) have the same value, - neither blockage function is written. */ - unit->needs_range_function - = (unit->needs_blockage_function - || GET_CODE (max_blockage) != CONST_STRING); - - if (unit->needs_range_function) - { - /* Compute the blockage range function and make an attribute - for writing its value. */ - newexp = operate_exp (RANGE_OP, min_blockage, max_blockage); - newexp = simplify_knowing (newexp, unit->condexp); - - str = attr_printf ((strlen (unit->name) - + sizeof "*_unit_blockage_range"), - "*%s_unit_blockage_range", unit->name); - make_internal_attr (str, newexp, (ATTR_STATIC|ATTR_BLOCKAGE|ATTR_UNSIGNED)); - } + tests[i - 2] + = insert_right_side (IOR, tests[i - 2], newtest, + insn_code, insn_index); - str = attr_printf (strlen (unit->name) + sizeof "*_unit_ready_cost", - "*%s_unit_ready_cost", unit->name); - make_internal_attr (str, readycost, ATTR_STATIC); + /* Delete this test/value. */ + for (j = i; j < len - 2; j++) + tests[j] = tests[j + 2]; + len -= 2; + i -= 2; } + else - { - /* Make an attribute for the ready_cost function. Simplifying - further with simplify_by_exploding doesn't win. */ - str = "*result_ready_cost"; - make_internal_attr (str, readycost, ATTR_NONE); - } + tests[i + 1] = newval; } - /* For each unit that requires a conflict cost function, make an attribute - that maps insns to the operation number. */ - for (unit = units; unit; unit = unit->next) - { - rtx caseexp; - - if (! unit->needs_conflict_function - && ! unit->needs_blockage_function) - continue; + /* If the last test in a COND has the same value + as the default value, that test isn't needed. */ - caseexp = rtx_alloc (COND); - XVEC (caseexp, 0) = rtvec_alloc ((unit->num_opclasses - 1) * 2); + while (len > 0 && attr_equal_p (tests[len - 1], new_defval)) + len -= 2; - for (op = unit->ops; op; op = op->next) + /* See if we changed anything. */ + if (len != XVECLEN (exp, 0) || new_defval != XEXP (exp, 1)) + allsame = 0; + else + for (i = 0; i < len; i++) + if (! attr_equal_p (tests[i], XVECEXP (exp, 0, i))) { - /* Make our adjustment to the COND being computed. If we are the - last operation class, place our values into the default of the - COND. */ - if (op->num == unit->num_opclasses - 1) - { - XEXP (caseexp, 1) = make_numeric_value (op->num); - } - else - { - XVECEXP (caseexp, 0, op->num * 2) = op->condexp; - XVECEXP (caseexp, 0, op->num * 2 + 1) - = make_numeric_value (op->num); - } + allsame = 0; + break; } - /* Simplifying caseexp with simplify_by_exploding doesn't win. */ - str = attr_printf (strlen (unit->name) + sizeof "*_cases", - "*%s_cases", unit->name); - make_internal_attr (str, caseexp, ATTR_SPECIAL); + if (len == 0) + { + if (GET_CODE (defval) == COND) + ret = simplify_cond (defval, insn_code, insn_index); + else + ret = defval; } -} - -/* Simplify EXP given KNOWN_TRUE. */ - -static rtx -simplify_knowing (rtx exp, rtx known_true) -{ - if (GET_CODE (exp) != CONST_STRING) + else if (allsame) + ret = exp; + else { - int unknown = 0, max; - max = max_attr_value (exp, &unknown); - if (! unknown) - { - exp = attr_rtx (IF_THEN_ELSE, known_true, exp, - make_numeric_value (max)); - exp = simplify_by_exploding (exp); - } + rtx newexp = rtx_alloc (COND); + + XVEC (newexp, 0) = rtvec_alloc (len); + memcpy (XVEC (newexp, 0)->elem, tests, len * sizeof (rtx)); + XEXP (newexp, 1) = new_defval; + ret = newexp; } - return exp; + free (tests); + return ret; } -/* Translate the CONST_STRING expressions in X to change the encoding of - value. On input, the value is a bitmask with a one bit for each unit - used; on output, the value is the unit number (zero based) if one - and only one unit is used or the one's complement of the bitmask. */ +/* Remove an insn entry from an attribute value. */ -static rtx -encode_units_mask (rtx x) +static void +remove_insn_ent (struct attr_value *av, struct insn_ent *ie) { - int i; - int j; - enum rtx_code code; - const char *fmt; - - code = GET_CODE (x); + struct insn_ent *previe; - switch (code) + if (av->first_insn == ie) + av->first_insn = ie->next; + else { - case CONST_STRING: - i = atoi (XSTR (x, 0)); - if (i < 0) - /* The sign bit encodes a one's complement mask. */ - abort (); - else if (i != 0 && i == (i & -i)) - /* Only one bit is set, so yield that unit number. */ - for (j = 0; (i >>= 1) != 0; j++) - ; - else - j = ~i; - return attr_rtx (CONST_STRING, attr_printf (MAX_DIGITS, "%d", j)); - - case REG: - case QUEUED: - case CONST_INT: - case CONST_DOUBLE: - case CONST_VECTOR: - case SYMBOL_REF: - case CODE_LABEL: - case PC: - case CC0: - case EQ_ATTR: - return x; - - default: - break; + for (previe = av->first_insn; previe->next != ie; previe = previe->next) + ; + previe->next = ie->next; } - /* Compare the elements. If any pair of corresponding elements - fail to match, return 0 for the whole things. */ - - fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - switch (fmt[i]) - { - case 'V': - case 'E': - for (j = 0; j < XVECLEN (x, i); j++) - XVECEXP (x, i, j) = encode_units_mask (XVECEXP (x, i, j)); - break; + av->num_insns--; + if (ie->def->insn_code == -1) + av->has_asm_insn = 0; - case 'e': - XEXP (x, i) = encode_units_mask (XEXP (x, i)); - break; - } - } - return x; + num_insn_ents--; } -/* Once all attributes and insns have been read and checked, we construct for - each attribute value a list of all the insns that have that value for - the attribute. */ +/* Insert an insn entry in an attribute value list. */ static void -fill_attr (struct attr_desc *attr) +insert_insn_ent (struct attr_value *av, struct insn_ent *ie) { - struct attr_value *av; - struct insn_ent *ie; - struct insn_def *id; - int i; - rtx value; - - /* Don't fill constant attributes. The value is independent of - any particular insn. */ - if (attr->is_const) - return; - - for (id = defs; id; id = id->next) - { - /* If no value is specified for this insn for this attribute, use the - default. */ - value = NULL; - if (XVEC (id->def, id->vec_idx)) - for (i = 0; i < XVECLEN (id->def, id->vec_idx); i++) - if (! strcmp (XSTR (XEXP (XVECEXP (id->def, id->vec_idx, i), 0), 0), - attr->name)) - value = XEXP (XVECEXP (id->def, id->vec_idx, i), 1); - - if (value == NULL) - av = attr->default_val; - else - av = get_attr_value (value, attr, id->insn_code); + ie->next = av->first_insn; + av->first_insn = ie; + av->num_insns++; + if (ie->def->insn_code == -1) + av->has_asm_insn = 1; - ie = oballoc (sizeof (struct insn_ent)); - ie->insn_code = id->insn_code; - ie->insn_index = id->insn_code; - insert_insn_ent (av, ie); - } + num_insn_ents++; } -/* Given an expression EXP, see if it is a COND or IF_THEN_ELSE that has a - test that checks relative positions of insns (uses MATCH_DUP or PC). - If so, replace it with what is obtained by passing the expression to - ADDRESS_FN. If not but it is a COND or IF_THEN_ELSE, call this routine - recursively on each value (including the default value). Otherwise, - return the value returned by NO_ADDRESS_FN applied to EXP. */ +/* This is a utility routine to take an expression that is a tree of either + AND or IOR expressions and insert a new term. The new term will be + inserted at the right side of the first node whose code does not match + the root. A new node will be created with the root's code. Its left + side will be the old right side and its right side will be the new + term. + + If the `term' is itself a tree, all its leaves will be inserted. */ static rtx -substitute_address (rtx exp, rtx (*no_address_fn) (rtx), - rtx (*address_fn) (rtx)) +insert_right_side (enum rtx_code code, rtx exp, rtx term, int insn_code, int insn_index) { - int i; rtx newexp; - if (GET_CODE (exp) == COND) - { - /* See if any tests use addresses. */ - address_used = 0; - for (i = 0; i < XVECLEN (exp, 0); i += 2) - walk_attr_value (XVECEXP (exp, 0, i)); - - if (address_used) - return (*address_fn) (exp); - - /* Make a new copy of this COND, replacing each element. */ - newexp = rtx_alloc (COND); - XVEC (newexp, 0) = rtvec_alloc (XVECLEN (exp, 0)); - for (i = 0; i < XVECLEN (exp, 0); i += 2) - { - XVECEXP (newexp, 0, i) = XVECEXP (exp, 0, i); - XVECEXP (newexp, 0, i + 1) - = substitute_address (XVECEXP (exp, 0, i + 1), - no_address_fn, address_fn); - } + /* Avoid consing in some special cases. */ + if (code == AND && term == true_rtx) + return exp; + if (code == AND && term == false_rtx) + return false_rtx; + if (code == AND && exp == true_rtx) + return term; + if (code == AND && exp == false_rtx) + return false_rtx; + if (code == IOR && term == true_rtx) + return true_rtx; + if (code == IOR && term == false_rtx) + return exp; + if (code == IOR && exp == true_rtx) + return true_rtx; + if (code == IOR && exp == false_rtx) + return term; + if (attr_equal_p (exp, term)) + return exp; - XEXP (newexp, 1) = substitute_address (XEXP (exp, 1), - no_address_fn, address_fn); + if (GET_CODE (term) == code) + { + exp = insert_right_side (code, exp, XEXP (term, 0), + insn_code, insn_index); + exp = insert_right_side (code, exp, XEXP (term, 1), + insn_code, insn_index); - return newexp; + return exp; } - else if (GET_CODE (exp) == IF_THEN_ELSE) + if (GET_CODE (exp) == code) { - address_used = 0; - walk_attr_value (XEXP (exp, 0)); - if (address_used) - return (*address_fn) (exp); - - return attr_rtx (IF_THEN_ELSE, - substitute_address (XEXP (exp, 0), - no_address_fn, address_fn), - substitute_address (XEXP (exp, 1), - no_address_fn, address_fn), - substitute_address (XEXP (exp, 2), - no_address_fn, address_fn)); + rtx new = insert_right_side (code, XEXP (exp, 1), + term, insn_code, insn_index); + if (new != XEXP (exp, 1)) + /* Make a copy of this expression and call recursively. */ + newexp = attr_rtx (code, XEXP (exp, 0), new); + else + newexp = exp; + } + else + { + /* Insert the new term. */ + newexp = attr_rtx (code, exp, term); } - return (*no_address_fn) (exp); + return simplify_test_exp_in_temp (newexp, insn_code, insn_index); } -/* Make new attributes from the `length' attribute. The following are made, - each corresponding to a function called from `shorten_branches' or - `get_attr_length': - - *insn_default_length This is the length of the insn to be returned - by `get_attr_length' before `shorten_branches' - has been called. In each case where the length - depends on relative addresses, the largest - possible is used. This routine is also used - to compute the initial size of the insn. - - *insn_variable_length_p This returns 1 if the insn's length depends - on relative addresses, zero otherwise. +/* If we have an expression which AND's a bunch of + (not (eq_attrq "alternative" "n")) + terms, we may have covered all or all but one of the possible alternatives. + If so, we can optimize. Similarly for IOR's of EQ_ATTR. - *insn_current_length This is only called when it is known that the - insn has a variable length and returns the - current length, based on relative addresses. - */ + This routine is passed an expression and either AND or IOR. It returns a + bitmask indicating which alternatives are mentioned within EXP. */ -static void -make_length_attrs (void) +static int +compute_alternative_mask (rtx exp, enum rtx_code code) { - static const char *const new_names[] = {"*insn_default_length", - "*insn_variable_length_p", - "*insn_current_length"}; - static rtx (*const no_address_fn[]) (rtx) = {identity_fn, zero_fn, zero_fn}; - static rtx (*const address_fn[]) (rtx) = {max_fn, one_fn, identity_fn}; - size_t i; - struct attr_desc *length_attr, *new_attr; - struct attr_value *av, *new_av; - struct insn_ent *ie, *new_ie; - - /* See if length attribute is defined. If so, it must be numeric. Make - it special so we don't output anything for it. */ - length_attr = find_attr ("length", 0); - if (length_attr == 0) - return; + const char *string; + if (GET_CODE (exp) == code) + return compute_alternative_mask (XEXP (exp, 0), code) + | compute_alternative_mask (XEXP (exp, 1), code); - if (! length_attr->is_numeric) - fatal ("length attribute must be numeric"); + else if (code == AND && GET_CODE (exp) == NOT + && GET_CODE (XEXP (exp, 0)) == EQ_ATTR + && XSTR (XEXP (exp, 0), 0) == alternative_name) + string = XSTR (XEXP (exp, 0), 1); - length_attr->is_const = 0; - length_attr->is_special = 1; + else if (code == IOR && GET_CODE (exp) == EQ_ATTR + && XSTR (exp, 0) == alternative_name) + string = XSTR (exp, 1); - /* Make each new attribute, in turn. */ - for (i = 0; i < ARRAY_SIZE (new_names); i++) + else if (GET_CODE (exp) == EQ_ATTR_ALT) { - make_internal_attr (new_names[i], - substitute_address (length_attr->default_val->value, - no_address_fn[i], address_fn[i]), - ATTR_NONE); - new_attr = find_attr (new_names[i], 0); - for (av = length_attr->first_value; av; av = av->next) - for (ie = av->first_insn; ie; ie = ie->next) - { - new_av = get_attr_value (substitute_address (av->value, - no_address_fn[i], - address_fn[i]), - new_attr, ie->insn_code); - new_ie = oballoc (sizeof (struct insn_ent)); - new_ie->insn_code = ie->insn_code; - new_ie->insn_index = ie->insn_index; - insert_insn_ent (new_av, new_ie); - } + if (code == AND && XINT (exp, 1)) + return XINT (exp, 0); + + if (code == IOR && !XINT (exp, 1)) + return XINT (exp, 0); + + return 0; } + else + return 0; + + if (string[1] == 0) + return 1 << (string[0] - '0'); + return 1 << atoi (string); } -/* Utility functions called from above routine. */ +/* Given I, a single-bit mask, return RTX to compare the `alternative' + attribute with the value represented by that bit. */ static rtx -identity_fn (rtx exp) +make_alternative_compare (int mask) { - return exp; + return mk_attr_alt (mask); } -static rtx -zero_fn (rtx exp ATTRIBUTE_UNUSED) -{ - return make_numeric_value (0); -} +/* If we are processing an (eq_attr "attr" "value") test, we find the value + of "attr" for this insn code. From that value, we can compute a test + showing when the EQ_ATTR will be true. This routine performs that + computation. If a test condition involves an address, we leave the EQ_ATTR + intact because addresses are only valid for the `length' attribute. -static rtx -one_fn (rtx exp ATTRIBUTE_UNUSED) -{ - return make_numeric_value (1); -} + EXP is the EQ_ATTR expression and VALUE is the value of that attribute + for the insn corresponding to INSN_CODE and INSN_INDEX. */ static rtx -max_fn (rtx exp) -{ - int unknown; - return make_numeric_value (max_attr_value (exp, &unknown)); -} - -static void -write_length_unit_log (void) +evaluate_eq_attr (rtx exp, rtx value, int insn_code, int insn_index) { - struct attr_desc *length_attr = find_attr ("length", 0); - struct attr_value *av; - struct insn_ent *ie; - unsigned int length_unit_log, length_or; - int unknown = 0; - - if (length_attr == 0) - return; - length_or = or_attr_value (length_attr->default_val->value, &unknown); - for (av = length_attr->first_value; av; av = av->next) - for (ie = av->first_insn; ie; ie = ie->next) - length_or |= or_attr_value (av->value, &unknown); + rtx orexp, andexp; + rtx right; + rtx newexp; + int i; - if (unknown) - length_unit_log = 0; - else + switch (GET_CODE (value)) { - length_or = ~length_or; - for (length_unit_log = 0; length_or & 1; length_or >>= 1) - length_unit_log++; - } - printf ("int length_unit_log = %u;\n", length_unit_log); -} + case CONST_STRING: + if (! strcmp_check (XSTR (value, 0), XSTR (exp, 1))) + newexp = true_rtx; + else + newexp = false_rtx; + break; + + case SYMBOL_REF: + { + char *p; + char string[256]; + + gcc_assert (GET_CODE (exp) == EQ_ATTR); + gcc_assert (strlen (XSTR (exp, 0)) + strlen (XSTR (exp, 1)) + 2 + <= 256); + + strcpy (string, XSTR (exp, 0)); + strcat (string, "_"); + strcat (string, XSTR (exp, 1)); + for (p = string; *p; p++) + *p = TOUPPER (*p); + + newexp = attr_rtx (EQ, value, + attr_rtx (SYMBOL_REF, + DEF_ATTR_STRING (string))); + break; + } -/* Take a COND expression and see if any of the conditions in it can be - simplified. If any are known true or known false for the particular insn - code, the COND can be further simplified. + case COND: + /* We construct an IOR of all the cases for which the + requested attribute value is present. Since we start with + FALSE, if it is not present, FALSE will be returned. + + Each case is the AND of the NOT's of the previous conditions with the + current condition; in the default case the current condition is TRUE. + + For each possible COND value, call ourselves recursively. + + The extra TRUE and FALSE expressions will be eliminated by another + call to the simplification routine. */ - Also call ourselves on any COND operations that are values of this COND. + orexp = false_rtx; + andexp = true_rtx; - We do not modify EXP; rather, we make and return a new rtx. */ + if (current_alternative_string) + clear_struct_flag (value); -static rtx -simplify_cond (rtx exp, int insn_code, int insn_index) -{ - int i, j; - /* We store the desired contents here, - then build a new expression if they don't match EXP. */ - rtx defval = XEXP (exp, 1); - rtx new_defval = XEXP (exp, 1); - int len = XVECLEN (exp, 0); - rtx *tests = xmalloc (len * sizeof (rtx)); - int allsame = 1; - rtx ret; + for (i = 0; i < XVECLEN (value, 0); i += 2) + { + rtx this = simplify_test_exp_in_temp (XVECEXP (value, 0, i), + insn_code, insn_index); - /* This lets us free all storage allocated below, if appropriate. */ - obstack_finish (rtl_obstack); + SIMPLIFY_ALTERNATIVE (this); - memcpy (tests, XVEC (exp, 0)->elem, len * sizeof (rtx)); + right = insert_right_side (AND, andexp, this, + insn_code, insn_index); + right = insert_right_side (AND, right, + evaluate_eq_attr (exp, + XVECEXP (value, 0, + i + 1), + insn_code, insn_index), + insn_code, insn_index); + orexp = insert_right_side (IOR, orexp, right, + insn_code, insn_index); - /* See if default value needs simplification. */ - if (GET_CODE (defval) == COND) - new_defval = simplify_cond (defval, insn_code, insn_index); + /* Add this condition into the AND expression. */ + newexp = attr_rtx (NOT, this); + andexp = insert_right_side (AND, andexp, newexp, + insn_code, insn_index); + } - /* Simplify the subexpressions, and see what tests we can get rid of. */ + /* Handle the default case. */ + right = insert_right_side (AND, andexp, + evaluate_eq_attr (exp, XEXP (value, 1), + insn_code, insn_index), + insn_code, insn_index); + newexp = insert_right_side (IOR, orexp, right, insn_code, insn_index); + break; - for (i = 0; i < len; i += 2) + default: + gcc_unreachable (); + } + + /* If uses an address, must return original expression. But set the + ATTR_IND_SIMPLIFIED_P bit so we don't try to simplify it again. */ + + address_used = 0; + walk_attr_value (newexp); + + if (address_used) { - rtx newtest, newval; + /* This had `&& current_alternative_string', which seems to be wrong. */ + if (! ATTR_IND_SIMPLIFIED_P (exp)) + return copy_rtx_unchanging (exp); + return exp; + } + else + return newexp; +} - /* Simplify this test. */ - newtest = simplify_test_exp_in_temp (tests[i], insn_code, insn_index); - tests[i] = newtest; +/* This routine is called when an AND of a term with a tree of AND's is + encountered. If the term or its complement is present in the tree, it + can be replaced with TRUE or FALSE, respectively. - newval = tests[i + 1]; - /* See if this value may need simplification. */ - if (GET_CODE (newval) == COND) - newval = simplify_cond (newval, insn_code, insn_index); + Note that (eq_attr "att" "v1") and (eq_attr "att" "v2") cannot both + be true and hence are complementary. - /* Look for ways to delete or combine this test. */ - if (newtest == true_rtx) + There is one special case: If we see + (and (not (eq_attr "att" "v1")) + (eq_attr "att" "v2")) + this can be replaced by (eq_attr "att" "v2"). To do this we need to + replace the term, not anything in the AND tree. So we pass a pointer to + the term. */ + +static rtx +simplify_and_tree (rtx exp, rtx *pterm, int insn_code, int insn_index) +{ + rtx left, right; + rtx newexp; + rtx temp; + int left_eliminates_term, right_eliminates_term; + + if (GET_CODE (exp) == AND) + { + left = simplify_and_tree (XEXP (exp, 0), pterm, insn_code, insn_index); + right = simplify_and_tree (XEXP (exp, 1), pterm, insn_code, insn_index); + if (left != XEXP (exp, 0) || right != XEXP (exp, 1)) { - /* If test is true, make this value the default - and discard this + any following tests. */ - len = i; - defval = tests[i + 1]; - new_defval = newval; + newexp = attr_rtx (AND, left, right); + + exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index); } + } - else if (newtest == false_rtx) + else if (GET_CODE (exp) == IOR) + { + /* For the IOR case, we do the same as above, except that we can + only eliminate `term' if both sides of the IOR would do so. */ + temp = *pterm; + left = simplify_and_tree (XEXP (exp, 0), &temp, insn_code, insn_index); + left_eliminates_term = (temp == true_rtx); + + temp = *pterm; + right = simplify_and_tree (XEXP (exp, 1), &temp, insn_code, insn_index); + right_eliminates_term = (temp == true_rtx); + + if (left_eliminates_term && right_eliminates_term) + *pterm = true_rtx; + + if (left != XEXP (exp, 0) || right != XEXP (exp, 1)) { - /* If test is false, discard it and its value. */ - for (j = i; j < len - 2; j++) - tests[j] = tests[j + 2]; - len -= 2; + newexp = attr_rtx (IOR, left, right); + + exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index); } + } - else if (i > 0 && attr_equal_p (newval, tests[i - 1])) - { - /* If this value and the value for the prev test are the same, - merge the tests. */ + /* Check for simplifications. Do some extra checking here since this + routine is called so many times. */ - tests[i - 2] - = insert_right_side (IOR, tests[i - 2], newtest, - insn_code, insn_index); + if (exp == *pterm) + return true_rtx; - /* Delete this test/value. */ - for (j = i; j < len - 2; j++) - tests[j] = tests[j + 2]; - len -= 2; - } + else if (GET_CODE (exp) == NOT && XEXP (exp, 0) == *pterm) + return false_rtx; - else - tests[i + 1] = newval; - } + else if (GET_CODE (*pterm) == NOT && exp == XEXP (*pterm, 0)) + return false_rtx; - /* If the last test in a COND has the same value - as the default value, that test isn't needed. */ + else if (GET_CODE (exp) == EQ_ATTR_ALT && GET_CODE (*pterm) == EQ_ATTR_ALT) + { + if (attr_alt_subset_p (*pterm, exp)) + return true_rtx; - while (len > 0 && attr_equal_p (tests[len - 1], new_defval)) - len -= 2; + if (attr_alt_subset_of_compl_p (*pterm, exp)) + return false_rtx; - /* See if we changed anything. */ - if (len != XVECLEN (exp, 0) || new_defval != XEXP (exp, 1)) - allsame = 0; - else - for (i = 0; i < len; i++) - if (! attr_equal_p (tests[i], XVECEXP (exp, 0, i))) - { - allsame = 0; - break; - } + if (attr_alt_subset_p (exp, *pterm)) + *pterm = true_rtx; + + return exp; + } - if (len == 0) + else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == EQ_ATTR) { - if (GET_CODE (defval) == COND) - ret = simplify_cond (defval, insn_code, insn_index); + if (XSTR (exp, 0) != XSTR (*pterm, 0)) + return exp; + + if (! strcmp_check (XSTR (exp, 1), XSTR (*pterm, 1))) + return true_rtx; else - ret = defval; + return false_rtx; } - else if (allsame) - ret = exp; - else + + else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT + && GET_CODE (XEXP (exp, 0)) == EQ_ATTR) { - rtx newexp = rtx_alloc (COND); + if (XSTR (*pterm, 0) != XSTR (XEXP (exp, 0), 0)) + return exp; - XVEC (newexp, 0) = rtvec_alloc (len); - memcpy (XVEC (newexp, 0)->elem, tests, len * sizeof (rtx)); - XEXP (newexp, 1) = new_defval; - ret = newexp; + if (! strcmp_check (XSTR (*pterm, 1), XSTR (XEXP (exp, 0), 1))) + return false_rtx; + else + return true_rtx; } - free (tests); - return ret; -} -/* Remove an insn entry from an attribute value. */ + else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT + && GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR) + { + if (XSTR (exp, 0) != XSTR (XEXP (*pterm, 0), 0)) + return exp; -static void -remove_insn_ent (struct attr_value *av, struct insn_ent *ie) -{ - struct insn_ent *previe; + if (! strcmp_check (XSTR (exp, 1), XSTR (XEXP (*pterm, 0), 1))) + return false_rtx; + else + *pterm = true_rtx; + } - if (av->first_insn == ie) - av->first_insn = ie->next; - else + else if (GET_CODE (exp) == NOT && GET_CODE (*pterm) == NOT) { - for (previe = av->first_insn; previe->next != ie; previe = previe->next) - ; - previe->next = ie->next; + if (attr_equal_p (XEXP (exp, 0), XEXP (*pterm, 0))) + return true_rtx; } - av->num_insns--; - if (ie->insn_code == -1) - av->has_asm_insn = 0; - - num_insn_ents--; -} + else if (GET_CODE (exp) == NOT) + { + if (attr_equal_p (XEXP (exp, 0), *pterm)) + return false_rtx; + } -/* Insert an insn entry in an attribute value list. */ + else if (GET_CODE (*pterm) == NOT) + { + if (attr_equal_p (XEXP (*pterm, 0), exp)) + return false_rtx; + } -static void -insert_insn_ent (struct attr_value *av, struct insn_ent *ie) -{ - ie->next = av->first_insn; - av->first_insn = ie; - av->num_insns++; - if (ie->insn_code == -1) - av->has_asm_insn = 1; + else if (attr_equal_p (exp, *pterm)) + return true_rtx; - num_insn_ents++; + return exp; } -/* This is a utility routine to take an expression that is a tree of either - AND or IOR expressions and insert a new term. The new term will be - inserted at the right side of the first node whose code does not match - the root. A new node will be created with the root's code. Its left - side will be the old right side and its right side will be the new - term. - - If the `term' is itself a tree, all its leaves will be inserted. */ +/* Similar to `simplify_and_tree', but for IOR trees. */ static rtx -insert_right_side (enum rtx_code code, rtx exp, rtx term, int insn_code, int insn_index) +simplify_or_tree (rtx exp, rtx *pterm, int insn_code, int insn_index) { + rtx left, right; rtx newexp; + rtx temp; + int left_eliminates_term, right_eliminates_term; - /* Avoid consing in some special cases. */ - if (code == AND && term == true_rtx) - return exp; - if (code == AND && term == false_rtx) - return false_rtx; - if (code == AND && exp == true_rtx) - return term; - if (code == AND && exp == false_rtx) - return false_rtx; - if (code == IOR && term == true_rtx) - return true_rtx; - if (code == IOR && term == false_rtx) - return exp; - if (code == IOR && exp == true_rtx) - return true_rtx; - if (code == IOR && exp == false_rtx) - return term; - if (attr_equal_p (exp, term)) - return exp; - - if (GET_CODE (term) == code) - { - exp = insert_right_side (code, exp, XEXP (term, 0), - insn_code, insn_index); - exp = insert_right_side (code, exp, XEXP (term, 1), - insn_code, insn_index); - - return exp; - } - - if (GET_CODE (exp) == code) - { - rtx new = insert_right_side (code, XEXP (exp, 1), - term, insn_code, insn_index); - if (new != XEXP (exp, 1)) - /* Make a copy of this expression and call recursively. */ - newexp = attr_rtx (code, XEXP (exp, 0), new); - else - newexp = exp; - } - else - { - /* Insert the new term. */ - newexp = attr_rtx (code, exp, term); - } - - return simplify_test_exp_in_temp (newexp, insn_code, insn_index); -} - -/* If we have an expression which AND's a bunch of - (not (eq_attrq "alternative" "n")) - terms, we may have covered all or all but one of the possible alternatives. - If so, we can optimize. Similarly for IOR's of EQ_ATTR. - - This routine is passed an expression and either AND or IOR. It returns a - bitmask indicating which alternatives are mentioned within EXP. */ - -static int -compute_alternative_mask (rtx exp, enum rtx_code code) -{ - const char *string; - if (GET_CODE (exp) == code) - return compute_alternative_mask (XEXP (exp, 0), code) - | compute_alternative_mask (XEXP (exp, 1), code); - - else if (code == AND && GET_CODE (exp) == NOT - && GET_CODE (XEXP (exp, 0)) == EQ_ATTR - && XSTR (XEXP (exp, 0), 0) == alternative_name) - string = XSTR (XEXP (exp, 0), 1); - - else if (code == IOR && GET_CODE (exp) == EQ_ATTR - && XSTR (exp, 0) == alternative_name) - string = XSTR (exp, 1); - - else - return 0; - - if (string[1] == 0) - return 1 << (string[0] - '0'); - return 1 << atoi (string); -} - -/* Given I, a single-bit mask, return RTX to compare the `alternative' - attribute with the value represented by that bit. */ - -static rtx -make_alternative_compare (int mask) -{ - rtx newexp; - int i; - - /* Find the bit. */ - for (i = 0; (mask & (1 << i)) == 0; i++) - ; - - newexp = attr_rtx (EQ_ATTR, alternative_name, attr_numeral (i)); - ATTR_IND_SIMPLIFIED_P (newexp) = 1; - - return newexp; -} - -/* If we are processing an (eq_attr "attr" "value") test, we find the value - of "attr" for this insn code. From that value, we can compute a test - showing when the EQ_ATTR will be true. This routine performs that - computation. If a test condition involves an address, we leave the EQ_ATTR - intact because addresses are only valid for the `length' attribute. - - EXP is the EQ_ATTR expression and VALUE is the value of that attribute - for the insn corresponding to INSN_CODE and INSN_INDEX. */ - -static rtx -evaluate_eq_attr (rtx exp, rtx value, int insn_code, int insn_index) -{ - rtx orexp, andexp; - rtx right; - rtx newexp; - int i; - - if (GET_CODE (value) == CONST_STRING) - { - if (! strcmp (XSTR (value, 0), XSTR (exp, 1))) - newexp = true_rtx; - else - newexp = false_rtx; - } - else if (GET_CODE (value) == SYMBOL_REF) - { - char *p; - char string[256]; - - if (GET_CODE (exp) != EQ_ATTR) - abort (); - - if (strlen (XSTR (exp, 0)) + strlen (XSTR (exp, 1)) + 2 > 256) - abort (); - - strcpy (string, XSTR (exp, 0)); - strcat (string, "_"); - strcat (string, XSTR (exp, 1)); - for (p = string; *p; p++) - *p = TOUPPER (*p); - - newexp = attr_rtx (EQ, value, - attr_rtx (SYMBOL_REF, - attr_string (string, strlen (string)))); - } - else if (GET_CODE (value) == COND) - { - /* We construct an IOR of all the cases for which the requested attribute - value is present. Since we start with FALSE, if it is not present, - FALSE will be returned. - - Each case is the AND of the NOT's of the previous conditions with the - current condition; in the default case the current condition is TRUE. - - For each possible COND value, call ourselves recursively. - - The extra TRUE and FALSE expressions will be eliminated by another - call to the simplification routine. */ - - orexp = false_rtx; - andexp = true_rtx; - - if (current_alternative_string) - clear_struct_flag (value); - - for (i = 0; i < XVECLEN (value, 0); i += 2) - { - rtx this = simplify_test_exp_in_temp (XVECEXP (value, 0, i), - insn_code, insn_index); - - SIMPLIFY_ALTERNATIVE (this); - - right = insert_right_side (AND, andexp, this, - insn_code, insn_index); - right = insert_right_side (AND, right, - evaluate_eq_attr (exp, - XVECEXP (value, 0, - i + 1), - insn_code, insn_index), - insn_code, insn_index); - orexp = insert_right_side (IOR, orexp, right, - insn_code, insn_index); - - /* Add this condition into the AND expression. */ - newexp = attr_rtx (NOT, this); - andexp = insert_right_side (AND, andexp, newexp, - insn_code, insn_index); - } - - /* Handle the default case. */ - right = insert_right_side (AND, andexp, - evaluate_eq_attr (exp, XEXP (value, 1), - insn_code, insn_index), - insn_code, insn_index); - newexp = insert_right_side (IOR, orexp, right, insn_code, insn_index); - } - else - abort (); - - /* If uses an address, must return original expression. But set the - ATTR_IND_SIMPLIFIED_P bit so we don't try to simplify it again. */ - - address_used = 0; - walk_attr_value (newexp); - - if (address_used) - { - /* This had `&& current_alternative_string', which seems to be wrong. */ - if (! ATTR_IND_SIMPLIFIED_P (exp)) - return copy_rtx_unchanging (exp); - return exp; - } - else - return newexp; -} - -/* This routine is called when an AND of a term with a tree of AND's is - encountered. If the term or its complement is present in the tree, it - can be replaced with TRUE or FALSE, respectively. - - Note that (eq_attr "att" "v1") and (eq_attr "att" "v2") cannot both - be true and hence are complementary. - - There is one special case: If we see - (and (not (eq_attr "att" "v1")) - (eq_attr "att" "v2")) - this can be replaced by (eq_attr "att" "v2"). To do this we need to - replace the term, not anything in the AND tree. So we pass a pointer to - the term. */ - -static rtx -simplify_and_tree (rtx exp, rtx *pterm, int insn_code, int insn_index) -{ - rtx left, right; - rtx newexp; - rtx temp; - int left_eliminates_term, right_eliminates_term; - - if (GET_CODE (exp) == AND) + if (GET_CODE (exp) == IOR) { - left = simplify_and_tree (XEXP (exp, 0), pterm, insn_code, insn_index); - right = simplify_and_tree (XEXP (exp, 1), pterm, insn_code, insn_index); + left = simplify_or_tree (XEXP (exp, 0), pterm, insn_code, insn_index); + right = simplify_or_tree (XEXP (exp, 1), pterm, insn_code, insn_index); if (left != XEXP (exp, 0) || right != XEXP (exp, 1)) { newexp = attr_rtx (GET_CODE (exp), left, right); @@ -2859,20 +2255,20 @@ simplify_and_tree (rtx exp, rtx *pterm, int insn_code, int insn_index) } } - else if (GET_CODE (exp) == IOR) + else if (GET_CODE (exp) == AND) { - /* For the IOR case, we do the same as above, except that we can - only eliminate `term' if both sides of the IOR would do so. */ + /* For the AND case, we do the same as above, except that we can + only eliminate `term' if both sides of the AND would do so. */ temp = *pterm; - left = simplify_and_tree (XEXP (exp, 0), &temp, insn_code, insn_index); - left_eliminates_term = (temp == true_rtx); + left = simplify_or_tree (XEXP (exp, 0), &temp, insn_code, insn_index); + left_eliminates_term = (temp == false_rtx); temp = *pterm; - right = simplify_and_tree (XEXP (exp, 1), &temp, insn_code, insn_index); - right_eliminates_term = (temp == true_rtx); + right = simplify_or_tree (XEXP (exp, 1), &temp, insn_code, insn_index); + right_eliminates_term = (temp == false_rtx); if (left_eliminates_term && right_eliminates_term) - *pterm = true_rtx; + *pterm = false_rtx; if (left != XEXP (exp, 0) || right != XEXP (exp, 1)) { @@ -2882,143 +2278,27 @@ simplify_and_tree (rtx exp, rtx *pterm, int insn_code, int insn_index) } } - /* Check for simplifications. Do some extra checking here since this - routine is called so many times. */ + if (attr_equal_p (exp, *pterm)) + return false_rtx; - if (exp == *pterm) + else if (GET_CODE (exp) == NOT && attr_equal_p (XEXP (exp, 0), *pterm)) return true_rtx; - else if (GET_CODE (exp) == NOT && XEXP (exp, 0) == *pterm) - return false_rtx; + else if (GET_CODE (*pterm) == NOT && attr_equal_p (XEXP (*pterm, 0), exp)) + return true_rtx; - else if (GET_CODE (*pterm) == NOT && exp == XEXP (*pterm, 0)) + else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT + && GET_CODE (XEXP (exp, 0)) == EQ_ATTR + && XSTR (*pterm, 0) == XSTR (XEXP (exp, 0), 0)) + *pterm = false_rtx; + + else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT + && GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR + && XSTR (exp, 0) == XSTR (XEXP (*pterm, 0), 0)) return false_rtx; - else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == EQ_ATTR) - { - if (XSTR (exp, 0) != XSTR (*pterm, 0)) - return exp; - - if (! strcmp (XSTR (exp, 1), XSTR (*pterm, 1))) - return true_rtx; - else - return false_rtx; - } - - else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT - && GET_CODE (XEXP (exp, 0)) == EQ_ATTR) - { - if (XSTR (*pterm, 0) != XSTR (XEXP (exp, 0), 0)) - return exp; - - if (! strcmp (XSTR (*pterm, 1), XSTR (XEXP (exp, 0), 1))) - return false_rtx; - else - return true_rtx; - } - - else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT - && GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR) - { - if (XSTR (exp, 0) != XSTR (XEXP (*pterm, 0), 0)) - return exp; - - if (! strcmp (XSTR (exp, 1), XSTR (XEXP (*pterm, 0), 1))) - return false_rtx; - else - *pterm = true_rtx; - } - - else if (GET_CODE (exp) == NOT && GET_CODE (*pterm) == NOT) - { - if (attr_equal_p (XEXP (exp, 0), XEXP (*pterm, 0))) - return true_rtx; - } - - else if (GET_CODE (exp) == NOT) - { - if (attr_equal_p (XEXP (exp, 0), *pterm)) - return false_rtx; - } - - else if (GET_CODE (*pterm) == NOT) - { - if (attr_equal_p (XEXP (*pterm, 0), exp)) - return false_rtx; - } - - else if (attr_equal_p (exp, *pterm)) - return true_rtx; - - return exp; -} - -/* Similar to `simplify_and_tree', but for IOR trees. */ - -static rtx -simplify_or_tree (rtx exp, rtx *pterm, int insn_code, int insn_index) -{ - rtx left, right; - rtx newexp; - rtx temp; - int left_eliminates_term, right_eliminates_term; - - if (GET_CODE (exp) == IOR) - { - left = simplify_or_tree (XEXP (exp, 0), pterm, insn_code, insn_index); - right = simplify_or_tree (XEXP (exp, 1), pterm, insn_code, insn_index); - if (left != XEXP (exp, 0) || right != XEXP (exp, 1)) - { - newexp = attr_rtx (GET_CODE (exp), left, right); - - exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index); - } - } - - else if (GET_CODE (exp) == AND) - { - /* For the AND case, we do the same as above, except that we can - only eliminate `term' if both sides of the AND would do so. */ - temp = *pterm; - left = simplify_or_tree (XEXP (exp, 0), &temp, insn_code, insn_index); - left_eliminates_term = (temp == false_rtx); - - temp = *pterm; - right = simplify_or_tree (XEXP (exp, 1), &temp, insn_code, insn_index); - right_eliminates_term = (temp == false_rtx); - - if (left_eliminates_term && right_eliminates_term) - *pterm = false_rtx; - - if (left != XEXP (exp, 0) || right != XEXP (exp, 1)) - { - newexp = attr_rtx (GET_CODE (exp), left, right); - - exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index); - } - } - - if (attr_equal_p (exp, *pterm)) - return false_rtx; - - else if (GET_CODE (exp) == NOT && attr_equal_p (XEXP (exp, 0), *pterm)) - return true_rtx; - - else if (GET_CODE (*pterm) == NOT && attr_equal_p (XEXP (*pterm, 0), exp)) - return true_rtx; - - else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT - && GET_CODE (XEXP (exp, 0)) == EQ_ATTR - && XSTR (*pterm, 0) == XSTR (XEXP (exp, 0), 0)) - *pterm = false_rtx; - - else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT - && GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR - && XSTR (exp, 0) == XSTR (XEXP (*pterm, 0), 0)) - return false_rtx; - - return exp; -} + return exp; +} /* Compute approximate cost of the expression. Used to decide whether expression is cheap enough for inline. */ @@ -3037,9 +2317,13 @@ attr_rtx_cost (rtx x) return 10; else return 0; + + case EQ_ATTR_ALT: + return 0; + case EQ_ATTR: /* Alternatives don't result into function call. */ - if (!strcmp (XSTR (x, 0), "alternative")) + if (!strcmp_check (XSTR (x, 0), alternative_name)) return 0; else return 5; @@ -3087,891 +2371,590 @@ simplify_test_exp_in_temp (rtx exp, int insn_code, int insn_index) return attr_copy_rtx (x); } -/* Given an expression, see if it can be simplified for a particular insn - code based on the values of other attributes being tested. This can - eliminate nested get_attr_... calls. - - Note that if an endless recursion is specified in the patterns, the - optimization will loop. However, it will do so in precisely the cases where - an infinite recursion loop could occur during compilation. It's better that - it occurs here! */ +/* Returns true if S1 is a subset of S2. */ -static rtx -simplify_test_exp (rtx exp, int insn_code, int insn_index) +static bool +attr_alt_subset_p (rtx s1, rtx s2) { - rtx left, right; - struct attr_desc *attr; - struct attr_value *av; - struct insn_ent *ie; - int i; - rtx newexp = exp; - - /* Don't re-simplify something we already simplified. */ - if (ATTR_IND_SIMPLIFIED_P (exp) || ATTR_CURR_SIMPLIFIED_P (exp)) - return exp; - - switch (GET_CODE (exp)) + switch ((XINT (s1, 1) << 1) | XINT (s2, 1)) { - case AND: - left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index); - SIMPLIFY_ALTERNATIVE (left); - if (left == false_rtx) - return false_rtx; - right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index); - SIMPLIFY_ALTERNATIVE (right); - if (left == false_rtx) - return false_rtx; - - /* If either side is an IOR and we have (eq_attr "alternative" ..") - present on both sides, apply the distributive law since this will - yield simplifications. */ - if ((GET_CODE (left) == IOR || GET_CODE (right) == IOR) - && compute_alternative_mask (left, IOR) - && compute_alternative_mask (right, IOR)) - { - if (GET_CODE (left) == IOR) - { - rtx tem = left; - left = right; - right = tem; - } - - newexp = attr_rtx (IOR, - attr_rtx (AND, left, XEXP (right, 0)), - attr_rtx (AND, left, XEXP (right, 1))); - - return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); - } - - /* Try with the term on both sides. */ - right = simplify_and_tree (right, &left, insn_code, insn_index); - if (left == XEXP (exp, 0) && right == XEXP (exp, 1)) - left = simplify_and_tree (left, &right, insn_code, insn_index); - - if (left == false_rtx || right == false_rtx) - return false_rtx; - else if (left == true_rtx) - { - return right; - } - else if (right == true_rtx) - { - return left; - } - /* See if all or all but one of the insn's alternatives are specified - in this tree. Optimize if so. */ - - else if (insn_code >= 0 - && (GET_CODE (left) == AND - || (GET_CODE (left) == NOT - && GET_CODE (XEXP (left, 0)) == EQ_ATTR - && XSTR (XEXP (left, 0), 0) == alternative_name) - || GET_CODE (right) == AND - || (GET_CODE (right) == NOT - && GET_CODE (XEXP (right, 0)) == EQ_ATTR - && XSTR (XEXP (right, 0), 0) == alternative_name))) - { - i = compute_alternative_mask (exp, AND); - if (i & ~insn_alternatives[insn_code]) - fatal ("invalid alternative specified for pattern number %d", - insn_index); - - /* If all alternatives are excluded, this is false. */ - i ^= insn_alternatives[insn_code]; - if (i == 0) - return false_rtx; - else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1) - { - /* If just one excluded, AND a comparison with that one to the - front of the tree. The others will be eliminated by - optimization. We do not want to do this if the insn has one - alternative and we have tested none of them! */ - left = make_alternative_compare (i); - right = simplify_and_tree (exp, &left, insn_code, insn_index); - newexp = attr_rtx (AND, left, right); - - return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); - } - } - - if (left != XEXP (exp, 0) || right != XEXP (exp, 1)) - { - newexp = attr_rtx (AND, left, right); - return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); - } - break; - - case IOR: - left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index); - SIMPLIFY_ALTERNATIVE (left); - if (left == true_rtx) - return true_rtx; - right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index); - SIMPLIFY_ALTERNATIVE (right); - if (right == true_rtx) - return true_rtx; - - right = simplify_or_tree (right, &left, insn_code, insn_index); - if (left == XEXP (exp, 0) && right == XEXP (exp, 1)) - left = simplify_or_tree (left, &right, insn_code, insn_index); - - if (right == true_rtx || left == true_rtx) - return true_rtx; - else if (left == false_rtx) - { - return right; - } - else if (right == false_rtx) - { - return left; - } - - /* Test for simple cases where the distributive law is useful. I.e., - convert (ior (and (x) (y)) - (and (x) (z))) - to (and (x) - (ior (y) (z))) - */ - - else if (GET_CODE (left) == AND && GET_CODE (right) == AND - && attr_equal_p (XEXP (left, 0), XEXP (right, 0))) - { - newexp = attr_rtx (IOR, XEXP (left, 1), XEXP (right, 1)); - - left = XEXP (left, 0); - right = newexp; - newexp = attr_rtx (AND, left, right); - return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); - } - - /* See if all or all but one of the insn's alternatives are specified - in this tree. Optimize if so. */ - - else if (insn_code >= 0 - && (GET_CODE (left) == IOR - || (GET_CODE (left) == EQ_ATTR - && XSTR (left, 0) == alternative_name) - || GET_CODE (right) == IOR - || (GET_CODE (right) == EQ_ATTR - && XSTR (right, 0) == alternative_name))) - { - i = compute_alternative_mask (exp, IOR); - if (i & ~insn_alternatives[insn_code]) - fatal ("invalid alternative specified for pattern number %d", - insn_index); - - /* If all alternatives are included, this is true. */ - i ^= insn_alternatives[insn_code]; - if (i == 0) - return true_rtx; - else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1) - { - /* If just one excluded, IOR a comparison with that one to the - front of the tree. The others will be eliminated by - optimization. We do not want to do this if the insn has one - alternative and we have tested none of them! */ - left = make_alternative_compare (i); - right = simplify_and_tree (exp, &left, insn_code, insn_index); - newexp = attr_rtx (IOR, attr_rtx (NOT, left), right); - - return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); - } - } - - if (left != XEXP (exp, 0) || right != XEXP (exp, 1)) - { - newexp = attr_rtx (IOR, left, right); - return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); - } - break; - - case NOT: - if (GET_CODE (XEXP (exp, 0)) == NOT) - { - left = SIMPLIFY_TEST_EXP (XEXP (XEXP (exp, 0), 0), - insn_code, insn_index); - SIMPLIFY_ALTERNATIVE (left); - return left; - } - - left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index); - SIMPLIFY_ALTERNATIVE (left); - if (GET_CODE (left) == NOT) - return XEXP (left, 0); - - if (left == false_rtx) - return true_rtx; - else if (left == true_rtx) - return false_rtx; - - /* Try to apply De`Morgan's laws. */ - else if (GET_CODE (left) == IOR) - { - newexp = attr_rtx (AND, - attr_rtx (NOT, XEXP (left, 0)), - attr_rtx (NOT, XEXP (left, 1))); - - newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); - } - else if (GET_CODE (left) == AND) - { - newexp = attr_rtx (IOR, - attr_rtx (NOT, XEXP (left, 0)), - attr_rtx (NOT, XEXP (left, 1))); - - newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); - } - else if (left != XEXP (exp, 0)) - { - newexp = attr_rtx (NOT, left); - } - break; - - case EQ_ATTR: - if (current_alternative_string && XSTR (exp, 0) == alternative_name) - return (XSTR (exp, 1) == current_alternative_string - ? true_rtx : false_rtx); - - /* Look at the value for this insn code in the specified attribute. - We normally can replace this comparison with the condition that - would give this insn the values being tested for. */ - if (XSTR (exp, 0) != alternative_name - && (attr = find_attr (XSTR (exp, 0), 0)) != NULL) - for (av = attr->first_value; av; av = av->next) - for (ie = av->first_insn; ie; ie = ie->next) - if (ie->insn_code == insn_code) - { - rtx x; - x = evaluate_eq_attr (exp, av->value, insn_code, insn_index); - x = SIMPLIFY_TEST_EXP (x, insn_code, insn_index); - if (attr_rtx_cost(x) < 20) - return x; - } - break; - - default: - break; - } - - /* We have already simplified this expression. Simplifying it again - won't buy anything unless we weren't given a valid insn code - to process (i.e., we are canonicalizing something.). */ - if (insn_code != -2 /* Seems wrong: && current_alternative_string. */ - && ! ATTR_IND_SIMPLIFIED_P (newexp)) - return copy_rtx_unchanging (newexp); - - return newexp; -} - -/* Optimize the attribute lists by seeing if we can determine conditional - values from the known values of other attributes. This will save subroutine - calls during the compilation. */ - -static void -optimize_attrs (void) -{ - struct attr_desc *attr; - struct attr_value *av; - struct insn_ent *ie; - rtx newexp; - int i; - struct attr_value_list - { - struct attr_value *av; - struct insn_ent *ie; - struct attr_desc *attr; - struct attr_value_list *next; - }; - struct attr_value_list **insn_code_values; - struct attr_value_list *ivbuf; - struct attr_value_list *iv; - - /* For each insn code, make a list of all the insn_ent's for it, - for all values for all attributes. */ - - if (num_insn_ents == 0) - return; - - /* Make 2 extra elements, for "code" values -2 and -1. */ - insn_code_values = xcalloc ((insn_code_number + 2), - sizeof (struct attr_value_list *)); - - /* Offset the table address so we can index by -2 or -1. */ - insn_code_values += 2; - - iv = ivbuf = xmalloc (num_insn_ents * sizeof (struct attr_value_list)); - - for (i = 0; i < MAX_ATTRS_INDEX; i++) - for (attr = attrs[i]; attr; attr = attr->next) - for (av = attr->first_value; av; av = av->next) - for (ie = av->first_insn; ie; ie = ie->next) - { - iv->attr = attr; - iv->av = av; - iv->ie = ie; - iv->next = insn_code_values[ie->insn_code]; - insn_code_values[ie->insn_code] = iv; - iv++; - } + case (0 << 1) | 0: + return !(XINT (s1, 0) &~ XINT (s2, 0)); - /* Sanity check on num_insn_ents. */ - if (iv != ivbuf + num_insn_ents) - abort (); + case (0 << 1) | 1: + return !(XINT (s1, 0) & XINT (s2, 0)); - /* Process one insn code at a time. */ - for (i = -2; i < insn_code_number; i++) + case (1 << 1) | 0: + return false; + + case (1 << 1) | 1: + return !(XINT (s2, 0) &~ XINT (s1, 0)); + + default: + gcc_unreachable (); + } +} + +/* Returns true if S1 is a subset of complement of S2. */ + +static bool +attr_alt_subset_of_compl_p (rtx s1, rtx s2) +{ + switch ((XINT (s1, 1) << 1) | XINT (s2, 1)) { - /* Clear the ATTR_CURR_SIMPLIFIED_P flag everywhere relevant. - We use it to mean "already simplified for this insn". */ - for (iv = insn_code_values[i]; iv; iv = iv->next) - clear_struct_flag (iv->av->value); + case (0 << 1) | 0: + return !(XINT (s1, 0) & XINT (s2, 0)); - for (iv = insn_code_values[i]; iv; iv = iv->next) - { - struct obstack *old = rtl_obstack; + case (0 << 1) | 1: + return !(XINT (s1, 0) & ~XINT (s2, 0)); - attr = iv->attr; - av = iv->av; - ie = iv->ie; - if (GET_CODE (av->value) != COND) - continue; + case (1 << 1) | 0: + return !(XINT (s2, 0) &~ XINT (s1, 0)); - rtl_obstack = temp_obstack; - newexp = av->value; - while (GET_CODE (newexp) == COND) - { - rtx newexp2 = simplify_cond (newexp, ie->insn_code, - ie->insn_index); - if (newexp2 == newexp) - break; - newexp = newexp2; - } + case (1 << 1) | 1: + return false; - rtl_obstack = old; - if (newexp != av->value) - { - newexp = attr_copy_rtx (newexp); - remove_insn_ent (av, ie); - av = get_attr_value (newexp, attr, ie->insn_code); - iv->av = av; - insert_insn_ent (av, ie); - } - } + default: + gcc_unreachable (); } - - free (ivbuf); - free (insn_code_values - 2); } -/* If EXP is a suitable expression, reorganize it by constructing an - equivalent expression that is a COND with the tests being all combinations - of attribute values and the values being simple constants. */ +/* Return EQ_ATTR_ALT expression representing intersection of S1 and S2. */ static rtx -simplify_by_exploding (rtx exp) +attr_alt_intersection (rtx s1, rtx s2) { - rtx list = 0, link, condexp, defval = NULL_RTX; - struct dimension *space; - rtx *condtest, *condval; - int i, j, total, ndim = 0; - int most_tests, num_marks, new_marks; - rtx ret; + rtx result = rtx_alloc (EQ_ATTR_ALT); - /* Locate all the EQ_ATTR expressions. */ - if (! find_and_mark_used_attributes (exp, &list, &ndim) || ndim == 0) + switch ((XINT (s1, 1) << 1) | XINT (s2, 1)) { - unmark_used_attributes (list, 0, 0); - return exp; + case (0 << 1) | 0: + XINT (result, 0) = XINT (s1, 0) & XINT (s2, 0); + break; + case (0 << 1) | 1: + XINT (result, 0) = XINT (s1, 0) & ~XINT (s2, 0); + break; + case (1 << 1) | 0: + XINT (result, 0) = XINT (s2, 0) & ~XINT (s1, 0); + break; + case (1 << 1) | 1: + XINT (result, 0) = XINT (s1, 0) | XINT (s2, 0); + break; + default: + gcc_unreachable (); } + XINT (result, 1) = XINT (s1, 1) & XINT (s2, 1); + + return result; +} - /* Create an attribute space from the list of used attributes. For each - dimension in the attribute space, record the attribute, list of values - used, and number of values used. Add members to the list of values to - cover the domain of the attribute. This makes the expanded COND form - order independent. */ +/* Return EQ_ATTR_ALT expression representing union of S1 and S2. */ - space = xmalloc (ndim * sizeof (struct dimension)); +static rtx +attr_alt_union (rtx s1, rtx s2) +{ + rtx result = rtx_alloc (EQ_ATTR_ALT); - total = 1; - for (ndim = 0; list; ndim++) + switch ((XINT (s1, 1) << 1) | XINT (s2, 1)) { - /* Pull the first attribute value from the list and record that - attribute as another dimension in the attribute space. */ - const char *name = XSTR (XEXP (list, 0), 0); - rtx *prev; + case (0 << 1) | 0: + XINT (result, 0) = XINT (s1, 0) | XINT (s2, 0); + break; + case (0 << 1) | 1: + XINT (result, 0) = XINT (s2, 0) & ~XINT (s1, 0); + break; + case (1 << 1) | 0: + XINT (result, 0) = XINT (s1, 0) & ~XINT (s2, 0); + break; + case (1 << 1) | 1: + XINT (result, 0) = XINT (s1, 0) & XINT (s2, 0); + break; + default: + gcc_unreachable (); + } - if ((space[ndim].attr = find_attr (name, 0)) == 0 - || space[ndim].attr->is_numeric) - { - unmark_used_attributes (list, space, ndim); - return exp; - } + XINT (result, 1) = XINT (s1, 1) | XINT (s2, 1); + return result; +} - /* Add all remaining attribute values that refer to this attribute. */ - space[ndim].num_values = 0; - space[ndim].values = 0; - prev = &list; - for (link = list; link; link = *prev) - if (! strcmp (XSTR (XEXP (link, 0), 0), name)) - { - space[ndim].num_values++; - *prev = XEXP (link, 1); - XEXP (link, 1) = space[ndim].values; - space[ndim].values = link; - } - else - prev = &XEXP (link, 1); +/* Return EQ_ATTR_ALT expression representing complement of S. */ - /* Add sufficient members to the list of values to make the list - mutually exclusive and record the total size of the attribute - space. */ - total *= add_values_to_cover (&space[ndim]); - } +static rtx +attr_alt_complement (rtx s) +{ + rtx result = rtx_alloc (EQ_ATTR_ALT); - /* Sort the attribute space so that the attributes go from non-constant - to constant and from most values to least values. */ - for (i = 0; i < ndim; i++) - for (j = ndim - 1; j > i; j--) - if ((space[j-1].attr->is_const && !space[j].attr->is_const) - || space[j-1].num_values < space[j].num_values) - { - struct dimension tmp; - tmp = space[j]; - space[j] = space[j - 1]; - space[j - 1] = tmp; - } + XINT (result, 0) = XINT (s, 0); + XINT (result, 1) = 1 - XINT (s, 1); - /* Establish the initial current value. */ - for (i = 0; i < ndim; i++) - space[i].current_value = space[i].values; + return result; +} - condtest = xmalloc (total * sizeof (rtx)); - condval = xmalloc (total * sizeof (rtx)); +/* Tests whether a bit B belongs to the set represented by S. */ - /* Expand the tests and values by iterating over all values in the - attribute space. */ - for (i = 0;; i++) - { - condtest[i] = test_for_current_value (space, ndim); - condval[i] = simplify_with_current_value (exp, space, ndim); - if (! increment_current_value (space, ndim)) - break; - } - if (i != total - 1) - abort (); - - /* We are now finished with the original expression. */ - unmark_used_attributes (0, space, ndim); - free (space); - - /* Find the most used constant value and make that the default. */ - most_tests = -1; - for (i = num_marks = 0; i < total; i++) - if (GET_CODE (condval[i]) == CONST_STRING - && ! ATTR_EQ_ATTR_P (condval[i])) - { - /* Mark the unmarked constant value and count how many are marked. */ - ATTR_EQ_ATTR_P (condval[i]) = 1; - for (j = new_marks = 0; j < total; j++) - if (GET_CODE (condval[j]) == CONST_STRING - && ATTR_EQ_ATTR_P (condval[j])) - new_marks++; - if (new_marks - num_marks > most_tests) - { - most_tests = new_marks - num_marks; - defval = condval[i]; - } - num_marks = new_marks; - } - /* Clear all the marks. */ - for (i = 0; i < total; i++) - ATTR_EQ_ATTR_P (condval[i]) = 0; +static bool +attr_alt_bit_p (rtx s, int b) +{ + return XINT (s, 1) ^ ((XINT (s, 0) >> b) & 1); +} - /* Give up if nothing is constant. */ - if (num_marks == 0) - ret = exp; +/* Return EQ_ATTR_ALT expression representing set containing elements set + in E. */ + +static rtx +mk_attr_alt (int e) +{ + rtx result = rtx_alloc (EQ_ATTR_ALT); - /* If all values are the default, use that. */ - else if (total == most_tests) - ret = defval; + XINT (result, 0) = e; + XINT (result, 1) = 0; - /* Make a COND with the most common constant value the default. (A more - complex method where tests with the same value were combined didn't - seem to improve things.) */ - else - { - condexp = rtx_alloc (COND); - XVEC (condexp, 0) = rtvec_alloc ((total - most_tests) * 2); - XEXP (condexp, 1) = defval; - for (i = j = 0; i < total; i++) - if (condval[i] != defval) - { - XVECEXP (condexp, 0, 2 * j) = condtest[i]; - XVECEXP (condexp, 0, 2 * j + 1) = condval[i]; - j++; - } - ret = condexp; - } - free (condtest); - free (condval); - return ret; + return result; } -/* Set the ATTR_EQ_ATTR_P flag for all EQ_ATTR expressions in EXP and - verify that EXP can be simplified to a constant term if all the EQ_ATTR - tests have known value. */ +/* Given an expression, see if it can be simplified for a particular insn + code based on the values of other attributes being tested. This can + eliminate nested get_attr_... calls. -static int -find_and_mark_used_attributes (rtx exp, rtx *terms, int *nterms) + Note that if an endless recursion is specified in the patterns, the + optimization will loop. However, it will do so in precisely the cases where + an infinite recursion loop could occur during compilation. It's better that + it occurs here! */ + +static rtx +simplify_test_exp (rtx exp, int insn_code, int insn_index) { + rtx left, right; + struct attr_desc *attr; + struct attr_value *av; + struct insn_ent *ie; int i; + rtx newexp = exp; + bool left_alt, right_alt; + + /* Don't re-simplify something we already simplified. */ + if (ATTR_IND_SIMPLIFIED_P (exp) || ATTR_CURR_SIMPLIFIED_P (exp)) + return exp; switch (GET_CODE (exp)) { - case EQ_ATTR: - if (! ATTR_EQ_ATTR_P (exp)) + case AND: + left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index); + SIMPLIFY_ALTERNATIVE (left); + if (left == false_rtx) + return false_rtx; + right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index); + SIMPLIFY_ALTERNATIVE (right); + if (left == false_rtx) + return false_rtx; + + if (GET_CODE (left) == EQ_ATTR_ALT + && GET_CODE (right) == EQ_ATTR_ALT) { - rtx link = rtx_alloc (EXPR_LIST); - XEXP (link, 0) = exp; - XEXP (link, 1) = *terms; - *terms = link; - *nterms += 1; - ATTR_EQ_ATTR_P (exp) = 1; + exp = attr_alt_intersection (left, right); + return simplify_test_exp (exp, insn_code, insn_index); } - return 1; - case CONST_STRING: - case CONST_INT: - return 1; + /* If either side is an IOR and we have (eq_attr "alternative" ..") + present on both sides, apply the distributive law since this will + yield simplifications. */ + if ((GET_CODE (left) == IOR || GET_CODE (right) == IOR) + && compute_alternative_mask (left, IOR) + && compute_alternative_mask (right, IOR)) + { + if (GET_CODE (left) == IOR) + { + rtx tem = left; + left = right; + right = tem; + } - case IF_THEN_ELSE: - if (! find_and_mark_used_attributes (XEXP (exp, 2), terms, nterms)) - return 0; - case IOR: - case AND: - if (! find_and_mark_used_attributes (XEXP (exp, 1), terms, nterms)) - return 0; - case NOT: - if (! find_and_mark_used_attributes (XEXP (exp, 0), terms, nterms)) - return 0; - return 1; + newexp = attr_rtx (IOR, + attr_rtx (AND, left, XEXP (right, 0)), + attr_rtx (AND, left, XEXP (right, 1))); - case COND: - for (i = 0; i < XVECLEN (exp, 0); i++) - if (! find_and_mark_used_attributes (XVECEXP (exp, 0, i), terms, nterms)) - return 0; - if (! find_and_mark_used_attributes (XEXP (exp, 1), terms, nterms)) - return 0; - return 1; + return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); + } - default: - return 0; - } -} + /* Try with the term on both sides. */ + right = simplify_and_tree (right, &left, insn_code, insn_index); + if (left == XEXP (exp, 0) && right == XEXP (exp, 1)) + left = simplify_and_tree (left, &right, insn_code, insn_index); + + if (left == false_rtx || right == false_rtx) + return false_rtx; + else if (left == true_rtx) + { + return right; + } + else if (right == true_rtx) + { + return left; + } + /* See if all or all but one of the insn's alternatives are specified + in this tree. Optimize if so. */ -/* Clear the ATTR_EQ_ATTR_P flag in all EQ_ATTR expressions on LIST and - in the values of the NDIM-dimensional attribute space SPACE. */ + if (GET_CODE (left) == NOT) + left_alt = (GET_CODE (XEXP (left, 0)) == EQ_ATTR + && XSTR (XEXP (left, 0), 0) == alternative_name); + else + left_alt = (GET_CODE (left) == EQ_ATTR_ALT + && XINT (left, 1)); -static void -unmark_used_attributes (rtx list, struct dimension *space, int ndim) -{ - rtx link, exp; - int i; + if (GET_CODE (right) == NOT) + right_alt = (GET_CODE (XEXP (right, 0)) == EQ_ATTR + && XSTR (XEXP (right, 0), 0) == alternative_name); + else + right_alt = (GET_CODE (right) == EQ_ATTR_ALT + && XINT (right, 1)); + + if (insn_code >= 0 + && (GET_CODE (left) == AND + || left_alt + || GET_CODE (right) == AND + || right_alt)) + { + i = compute_alternative_mask (exp, AND); + if (i & ~insn_alternatives[insn_code]) + fatal ("invalid alternative specified for pattern number %d", + insn_index); - for (i = 0; i < ndim; i++) - unmark_used_attributes (space[i].values, 0, 0); + /* If all alternatives are excluded, this is false. */ + i ^= insn_alternatives[insn_code]; + if (i == 0) + return false_rtx; + else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1) + { + /* If just one excluded, AND a comparison with that one to the + front of the tree. The others will be eliminated by + optimization. We do not want to do this if the insn has one + alternative and we have tested none of them! */ + left = make_alternative_compare (i); + right = simplify_and_tree (exp, &left, insn_code, insn_index); + newexp = attr_rtx (AND, left, right); - for (link = list; link; link = XEXP (link, 1)) - { - exp = XEXP (link, 0); - if (GET_CODE (exp) == EQ_ATTR) - ATTR_EQ_ATTR_P (exp) = 0; - } -} + return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); + } + } -/* Update the attribute dimension DIM so that all values of the attribute - are tested. Return the updated number of values. */ + if (left != XEXP (exp, 0) || right != XEXP (exp, 1)) + { + newexp = attr_rtx (AND, left, right); + return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); + } + break; -static int -add_values_to_cover (struct dimension *dim) -{ - struct attr_value *av; - rtx exp, link, *prev; - int nalt = 0; - - for (av = dim->attr->first_value; av; av = av->next) - if (GET_CODE (av->value) == CONST_STRING) - nalt++; - - if (nalt < dim->num_values) - abort (); - else if (nalt == dim->num_values) - /* OK. */ - ; - else if (nalt * 2 < dim->num_values * 3) - { - /* Most all the values of the attribute are used, so add all the unused - values. */ - prev = &dim->values; - for (link = dim->values; link; link = *prev) - prev = &XEXP (link, 1); - - for (av = dim->attr->first_value; av; av = av->next) - if (GET_CODE (av->value) == CONST_STRING) - { - exp = attr_eq (dim->attr->name, XSTR (av->value, 0)); - if (ATTR_EQ_ATTR_P (exp)) - continue; + case IOR: + left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index); + SIMPLIFY_ALTERNATIVE (left); + if (left == true_rtx) + return true_rtx; + right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index); + SIMPLIFY_ALTERNATIVE (right); + if (right == true_rtx) + return true_rtx; - link = rtx_alloc (EXPR_LIST); - XEXP (link, 0) = exp; - XEXP (link, 1) = 0; - *prev = link; - prev = &XEXP (link, 1); - } - dim->num_values = nalt; - } - else - { - rtx orexp = false_rtx; + if (GET_CODE (left) == EQ_ATTR_ALT + && GET_CODE (right) == EQ_ATTR_ALT) + { + exp = attr_alt_union (left, right); + return simplify_test_exp (exp, insn_code, insn_index); + } + + right = simplify_or_tree (right, &left, insn_code, insn_index); + if (left == XEXP (exp, 0) && right == XEXP (exp, 1)) + left = simplify_or_tree (left, &right, insn_code, insn_index); + + if (right == true_rtx || left == true_rtx) + return true_rtx; + else if (left == false_rtx) + { + return right; + } + else if (right == false_rtx) + { + return left; + } + + /* Test for simple cases where the distributive law is useful. I.e., + convert (ior (and (x) (y)) + (and (x) (z))) + to (and (x) + (ior (y) (z))) + */ - /* Very few values are used, so compute a mutually exclusive - expression. (We could do this for numeric values if that becomes - important.) */ - prev = &dim->values; - for (link = dim->values; link; link = *prev) + else if (GET_CODE (left) == AND && GET_CODE (right) == AND + && attr_equal_p (XEXP (left, 0), XEXP (right, 0))) { - orexp = insert_right_side (IOR, orexp, XEXP (link, 0), -2, -2); - prev = &XEXP (link, 1); - } - link = rtx_alloc (EXPR_LIST); - XEXP (link, 0) = attr_rtx (NOT, orexp); - XEXP (link, 1) = 0; - *prev = link; - dim->num_values++; - } - return dim->num_values; -} + newexp = attr_rtx (IOR, XEXP (left, 1), XEXP (right, 1)); -/* Increment the current value for the NDIM-dimensional attribute space SPACE - and return FALSE if the increment overflowed. */ + left = XEXP (left, 0); + right = newexp; + newexp = attr_rtx (AND, left, right); + return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); + } -static int -increment_current_value (struct dimension *space, int ndim) -{ - int i; + /* See if all or all but one of the insn's alternatives are specified + in this tree. Optimize if so. */ - for (i = ndim - 1; i >= 0; i--) - { - if ((space[i].current_value = XEXP (space[i].current_value, 1)) == 0) - space[i].current_value = space[i].values; - else - return 1; - } - return 0; -} + else if (insn_code >= 0 + && (GET_CODE (left) == IOR + || (GET_CODE (left) == EQ_ATTR_ALT + && !XINT (left, 1)) + || (GET_CODE (left) == EQ_ATTR + && XSTR (left, 0) == alternative_name) + || GET_CODE (right) == IOR + || (GET_CODE (right) == EQ_ATTR_ALT + && !XINT (right, 1)) + || (GET_CODE (right) == EQ_ATTR + && XSTR (right, 0) == alternative_name))) + { + i = compute_alternative_mask (exp, IOR); + if (i & ~insn_alternatives[insn_code]) + fatal ("invalid alternative specified for pattern number %d", + insn_index); -/* Construct an expression corresponding to the current value for the - NDIM-dimensional attribute space SPACE. */ + /* If all alternatives are included, this is true. */ + i ^= insn_alternatives[insn_code]; + if (i == 0) + return true_rtx; + else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1) + { + /* If just one excluded, IOR a comparison with that one to the + front of the tree. The others will be eliminated by + optimization. We do not want to do this if the insn has one + alternative and we have tested none of them! */ + left = make_alternative_compare (i); + right = simplify_and_tree (exp, &left, insn_code, insn_index); + newexp = attr_rtx (IOR, attr_rtx (NOT, left), right); -static rtx -test_for_current_value (struct dimension *space, int ndim) -{ - int i; - rtx exp = true_rtx; + return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); + } + } - for (i = 0; i < ndim; i++) - exp = insert_right_side (AND, exp, XEXP (space[i].current_value, 0), - -2, -2); + if (left != XEXP (exp, 0) || right != XEXP (exp, 1)) + { + newexp = attr_rtx (IOR, left, right); + return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); + } + break; - return exp; -} + case NOT: + if (GET_CODE (XEXP (exp, 0)) == NOT) + { + left = SIMPLIFY_TEST_EXP (XEXP (XEXP (exp, 0), 0), + insn_code, insn_index); + SIMPLIFY_ALTERNATIVE (left); + return left; + } -/* Given the current value of the NDIM-dimensional attribute space SPACE, - set the corresponding EQ_ATTR expressions to that value and reduce - the expression EXP as much as possible. On input [and output], all - known EQ_ATTR expressions are set to FALSE. */ + left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index); + SIMPLIFY_ALTERNATIVE (left); + if (GET_CODE (left) == NOT) + return XEXP (left, 0); -static rtx -simplify_with_current_value (rtx exp, struct dimension *space, int ndim) -{ - int i; - rtx x; + if (left == false_rtx) + return true_rtx; + if (left == true_rtx) + return false_rtx; - /* Mark each current value as TRUE. */ - for (i = 0; i < ndim; i++) - { - x = XEXP (space[i].current_value, 0); - if (GET_CODE (x) == EQ_ATTR) - ATTR_EQ_ATTR_P (x) = 0; - } + if (GET_CODE (left) == EQ_ATTR_ALT) + { + exp = attr_alt_complement (left); + return simplify_test_exp (exp, insn_code, insn_index); + } - exp = simplify_with_current_value_aux (exp); + /* Try to apply De`Morgan's laws. */ + if (GET_CODE (left) == IOR) + { + newexp = attr_rtx (AND, + attr_rtx (NOT, XEXP (left, 0)), + attr_rtx (NOT, XEXP (left, 1))); - /* Change each current value back to FALSE. */ - for (i = 0; i < ndim; i++) - { - x = XEXP (space[i].current_value, 0); - if (GET_CODE (x) == EQ_ATTR) - ATTR_EQ_ATTR_P (x) = 1; - } + newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); + } + else if (GET_CODE (left) == AND) + { + newexp = attr_rtx (IOR, + attr_rtx (NOT, XEXP (left, 0)), + attr_rtx (NOT, XEXP (left, 1))); - return exp; -} + newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index); + } + else if (left != XEXP (exp, 0)) + { + newexp = attr_rtx (NOT, left); + } + break; -/* Reduce the expression EXP based on the ATTR_EQ_ATTR_P settings of - all EQ_ATTR expressions. */ + case EQ_ATTR_ALT: + if (current_alternative_string) + return attr_alt_bit_p (exp, atoi (current_alternative_string)) ? true_rtx : false_rtx; -static rtx -simplify_with_current_value_aux (rtx exp) -{ - int i; - rtx cond; + if (!XINT (exp, 0)) + return XINT (exp, 1) ? true_rtx : false_rtx; + break; - switch (GET_CODE (exp)) - { case EQ_ATTR: - if (ATTR_EQ_ATTR_P (exp)) - return false_rtx; - else - return true_rtx; - case CONST_STRING: - case CONST_INT: - return exp; - - case IF_THEN_ELSE: - cond = simplify_with_current_value_aux (XEXP (exp, 0)); - if (cond == true_rtx) - return simplify_with_current_value_aux (XEXP (exp, 1)); - else if (cond == false_rtx) - return simplify_with_current_value_aux (XEXP (exp, 2)); - else - return attr_rtx (IF_THEN_ELSE, cond, - simplify_with_current_value_aux (XEXP (exp, 1)), - simplify_with_current_value_aux (XEXP (exp, 2))); - - case IOR: - cond = simplify_with_current_value_aux (XEXP (exp, 1)); - if (cond == true_rtx) - return cond; - else if (cond == false_rtx) - return simplify_with_current_value_aux (XEXP (exp, 0)); - else - return attr_rtx (IOR, cond, - simplify_with_current_value_aux (XEXP (exp, 0))); - - case AND: - cond = simplify_with_current_value_aux (XEXP (exp, 1)); - if (cond == true_rtx) - return simplify_with_current_value_aux (XEXP (exp, 0)); - else if (cond == false_rtx) - return cond; - else - return attr_rtx (AND, cond, - simplify_with_current_value_aux (XEXP (exp, 0))); - - case NOT: - cond = simplify_with_current_value_aux (XEXP (exp, 0)); - if (cond == true_rtx) - return false_rtx; - else if (cond == false_rtx) - return true_rtx; - else - return attr_rtx (NOT, cond); + if (current_alternative_string && XSTR (exp, 0) == alternative_name) + return (XSTR (exp, 1) == current_alternative_string + ? true_rtx : false_rtx); - case COND: - for (i = 0; i < XVECLEN (exp, 0); i += 2) + if (XSTR (exp, 0) == alternative_name) { - cond = simplify_with_current_value_aux (XVECEXP (exp, 0, i)); - if (cond == true_rtx) - return simplify_with_current_value_aux (XVECEXP (exp, 0, i + 1)); - else if (cond == false_rtx) - continue; - else - abort (); /* With all EQ_ATTR's of known value, a case should - have been selected. */ + newexp = mk_attr_alt (1 << atoi (XSTR (exp, 1))); + break; } - return simplify_with_current_value_aux (XEXP (exp, 1)); + + /* Look at the value for this insn code in the specified attribute. + We normally can replace this comparison with the condition that + would give this insn the values being tested for. */ + if (XSTR (exp, 0) != alternative_name + && (attr = find_attr (&XSTR (exp, 0), 0)) != NULL) + for (av = attr->first_value; av; av = av->next) + for (ie = av->first_insn; ie; ie = ie->next) + if (ie->def->insn_code == insn_code) + { + rtx x; + x = evaluate_eq_attr (exp, av->value, insn_code, insn_index); + x = SIMPLIFY_TEST_EXP (x, insn_code, insn_index); + if (attr_rtx_cost(x) < 20) + return x; + } + break; default: - abort (); + break; } + + /* We have already simplified this expression. Simplifying it again + won't buy anything unless we weren't given a valid insn code + to process (i.e., we are canonicalizing something.). */ + if (insn_code != -2 /* Seems wrong: && current_alternative_string. */ + && ! ATTR_IND_SIMPLIFIED_P (newexp)) + return copy_rtx_unchanging (newexp); + + return newexp; } -/* Clear the ATTR_CURR_SIMPLIFIED_P flag in EXP and its subexpressions. */ +/* Optimize the attribute lists by seeing if we can determine conditional + values from the known values of other attributes. This will save subroutine + calls during the compilation. */ static void -clear_struct_flag (rtx x) +optimize_attrs (void) { + struct attr_desc *attr; + struct attr_value *av; + struct insn_ent *ie; + rtx newexp; int i; - int j; - enum rtx_code code; - const char *fmt; + struct attr_value_list + { + struct attr_value *av; + struct insn_ent *ie; + struct attr_desc *attr; + struct attr_value_list *next; + }; + struct attr_value_list **insn_code_values; + struct attr_value_list *ivbuf; + struct attr_value_list *iv; - ATTR_CURR_SIMPLIFIED_P (x) = 0; - if (ATTR_IND_SIMPLIFIED_P (x)) + /* For each insn code, make a list of all the insn_ent's for it, + for all values for all attributes. */ + + if (num_insn_ents == 0) return; - code = GET_CODE (x); + /* Make 2 extra elements, for "code" values -2 and -1. */ + insn_code_values = xcalloc ((insn_code_number + 2), + sizeof (struct attr_value_list *)); - switch (code) - { - case REG: - case QUEUED: - case CONST_INT: - case CONST_DOUBLE: - case CONST_VECTOR: - case SYMBOL_REF: - case CODE_LABEL: - case PC: - case CC0: - case EQ_ATTR: - case ATTR_FLAG: - return; + /* Offset the table address so we can index by -2 or -1. */ + insn_code_values += 2; - default: - break; - } + iv = ivbuf = xmalloc (num_insn_ents * sizeof (struct attr_value_list)); - /* Compare the elements. If any pair of corresponding elements - fail to match, return 0 for the whole things. */ + for (i = 0; i < MAX_ATTRS_INDEX; i++) + for (attr = attrs[i]; attr; attr = attr->next) + for (av = attr->first_value; av; av = av->next) + for (ie = av->first_insn; ie; ie = ie->next) + { + iv->attr = attr; + iv->av = av; + iv->ie = ie; + iv->next = insn_code_values[ie->def->insn_code]; + insn_code_values[ie->def->insn_code] = iv; + iv++; + } - fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + /* Sanity check on num_insn_ents. */ + gcc_assert (iv == ivbuf + num_insn_ents); + + /* Process one insn code at a time. */ + for (i = -2; i < insn_code_number; i++) { - switch (fmt[i]) - { - case 'V': - case 'E': - for (j = 0; j < XVECLEN (x, i); j++) - clear_struct_flag (XVECEXP (x, i, j)); - break; + /* Clear the ATTR_CURR_SIMPLIFIED_P flag everywhere relevant. + We use it to mean "already simplified for this insn". */ + for (iv = insn_code_values[i]; iv; iv = iv->next) + clear_struct_flag (iv->av->value); + + for (iv = insn_code_values[i]; iv; iv = iv->next) + { + struct obstack *old = rtl_obstack; - case 'e': - clear_struct_flag (XEXP (x, i)); - break; + attr = iv->attr; + av = iv->av; + ie = iv->ie; + if (GET_CODE (av->value) != COND) + continue; + + rtl_obstack = temp_obstack; + newexp = av->value; + while (GET_CODE (newexp) == COND) + { + rtx newexp2 = simplify_cond (newexp, ie->def->insn_code, + ie->def->insn_index); + if (newexp2 == newexp) + break; + newexp = newexp2; + } + + rtl_obstack = old; + if (newexp != av->value) + { + newexp = attr_copy_rtx (newexp); + remove_insn_ent (av, ie); + av = get_attr_value (newexp, attr, ie->def->insn_code); + iv->av = av; + insert_insn_ent (av, ie); + } } } + + free (ivbuf); + free (insn_code_values - 2); } -/* Return the number of RTX objects making up the expression X. - But if we count more than MAX objects, stop counting. */ +/* Clear the ATTR_CURR_SIMPLIFIED_P flag in EXP and its subexpressions. */ -static int -count_sub_rtxs (rtx x, int max) +static void +clear_struct_flag (rtx x) { int i; int j; enum rtx_code code; const char *fmt; - int total = 0; + + ATTR_CURR_SIMPLIFIED_P (x) = 0; + if (ATTR_IND_SIMPLIFIED_P (x)) + return; code = GET_CODE (x); switch (code) { case REG: - case QUEUED: case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -3981,7 +2964,7 @@ count_sub_rtxs (rtx x, int max) case CC0: case EQ_ATTR: case ATTR_FLAG: - return 1; + return; default: break; @@ -3993,24 +2976,19 @@ count_sub_rtxs (rtx x, int max) fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { - if (total >= max) - return total; - switch (fmt[i]) { case 'V': case 'E': for (j = 0; j < XVECLEN (x, i); j++) - total += count_sub_rtxs (XVECEXP (x, i, j), max); + clear_struct_flag (XVECEXP (x, i, j)); break; case 'e': - total += count_sub_rtxs (XEXP (x, i), max); + clear_struct_flag (XEXP (x, i)); break; } } - return total; - } /* Create table entries for DEFINE_ATTR. */ @@ -4025,7 +3003,7 @@ gen_attr (rtx exp, int lineno) /* Make a new attribute structure. Check for duplicate by looking at attr->default_val, since it is initialized by this routine. */ - attr = find_attr (XSTR (exp, 0), 1); + attr = find_attr (&XSTR (exp, 0), 1); if (attr->default_val) { message_with_line (lineno, "duplicate definition for attribute %s", @@ -4067,7 +3045,7 @@ gen_attr (rtx exp, int lineno) XEXP (exp, 2) = XEXP (XEXP (exp, 2), 0); } - if (! strcmp (attr->name, "length") && ! attr->is_numeric) + if (! strcmp_check (attr->name, length_str) && ! attr->is_numeric) { message_with_line (lineno, "`length' attribute must take numeric values"); @@ -4222,7 +3200,7 @@ gen_insn (rtx exp, int lineno) break; default: - abort (); + gcc_unreachable (); } } @@ -4259,95 +3237,6 @@ gen_delay (rtx def, int lineno) delays = delay; } -/* Process a DEFINE_FUNCTION_UNIT. - - This gives information about a function unit contained in the CPU. - We fill in a `struct function_unit_op' and a `struct function_unit' - with information used later by `expand_unit'. */ - -static void -gen_unit (rtx def, int lineno) -{ - struct function_unit *unit; - struct function_unit_op *op; - const char *name = XSTR (def, 0); - int multiplicity = XINT (def, 1); - int simultaneity = XINT (def, 2); - rtx condexp = XEXP (def, 3); - int ready_cost = MAX (XINT (def, 4), 1); - int issue_delay = MAX (XINT (def, 5), 1); - - /* See if we have already seen this function unit. If so, check that - the multiplicity and simultaneity values are the same. If not, make - a structure for this function unit. */ - for (unit = units; unit; unit = unit->next) - if (! strcmp (unit->name, name)) - { - if (unit->multiplicity != multiplicity - || unit->simultaneity != simultaneity) - { - message_with_line (lineno, - "differing specifications given for function unit %s", - unit->name); - message_with_line (unit->first_lineno, "previous definition"); - have_error = 1; - return; - } - break; - } - - if (unit == 0) - { - unit = oballoc (sizeof (struct function_unit)); - unit->name = name; - unit->multiplicity = multiplicity; - unit->simultaneity = simultaneity; - unit->issue_delay.min = unit->issue_delay.max = issue_delay; - unit->num = num_units++; - unit->num_opclasses = 0; - unit->condexp = false_rtx; - unit->ops = 0; - unit->next = units; - unit->first_lineno = lineno; - units = unit; - } - - /* Make a new operation class structure entry and initialize it. */ - op = oballoc (sizeof (struct function_unit_op)); - op->condexp = condexp; - op->num = unit->num_opclasses++; - op->ready = ready_cost; - op->issue_delay = issue_delay; - op->next = unit->ops; - op->lineno = lineno; - unit->ops = op; - num_unit_opclasses++; - - /* Set our issue expression based on whether or not an optional conflict - vector was specified. */ - if (XVEC (def, 6)) - { - /* Compute the IOR of all the specified expressions. */ - rtx orexp = false_rtx; - int i; - - for (i = 0; i < XVECLEN (def, 6); i++) - orexp = insert_right_side (IOR, orexp, XVECEXP (def, 6, i), -2, -2); - - op->conflict_exp = orexp; - extend_range (&unit->issue_delay, 1, issue_delay); - } - else - { - op->conflict_exp = true_rtx; - extend_range (&unit->issue_delay, issue_delay, issue_delay); - } - - /* Merge our conditional into that of the function unit so we can determine - which insns are used by the function unit. */ - unit->condexp = insert_right_side (IOR, unit->condexp, op->condexp, -2, -2); -} - /* Given a piece of RTX, print a C expression to test its truth value. We use AND and IOR both for logical and bit-wise operations, so interpret them as logical unless they are inside a comparison expression. @@ -4371,9 +3260,14 @@ write_test_expr (rtx exp, int flags) switch (code) { /* Binary operators. */ + case GEU: case GTU: + case LEU: case LTU: + printf ("(unsigned) "); + /* Fall through. */ + case EQ: case NE: - case GE: case GT: case GEU: case GTU: - case LE: case LT: case LEU: case LTU: + case GE: case GT: + case LE: case LT: comparison_operator = 1; case PLUS: case MINUS: case MULT: case DIV: case MOD: @@ -4450,7 +3344,7 @@ write_test_expr (rtx exp, int flags) printf (" >> "); break; default: - abort (); + gcc_unreachable (); } write_test_expr (XEXP (exp, 1), flags | comparison_operator); @@ -4484,12 +3378,58 @@ write_test_expr (rtx exp, int flags) printf ("-"); break; default: - abort (); + gcc_unreachable (); } write_test_expr (XEXP (exp, 0), flags); break; + case EQ_ATTR_ALT: + { + int set = XINT (exp, 0), bit = 0; + + if (flags & 1) + fatal ("EQ_ATTR_ALT not valid inside comparison"); + + if (!set) + fatal ("Empty EQ_ATTR_ALT should be optimized out"); + + if (!(set & (set - 1))) + { + if (!(set & 0xffff)) + { + bit += 16; + set >>= 16; + } + if (!(set & 0xff)) + { + bit += 8; + set >>= 8; + } + if (!(set & 0xf)) + { + bit += 4; + set >>= 4; + } + if (!(set & 0x3)) + { + bit += 2; + set >>= 2; + } + if (!(set & 1)) + bit++; + + printf ("which_alternative %s= %d", + XINT (exp, 1) ? "!" : "=", bit); + } + else + { + printf ("%s((1 << which_alternative) & 0x%x)", + XINT (exp, 1) ? "!" : "", set); + } + } + break; + /* Comparison test of an attribute with a value. Most of these will have been removed by optimization. Handle "alternative" specially and give error if EQ_ATTR present inside a comparison. */ @@ -4503,9 +3443,8 @@ write_test_expr (rtx exp, int flags) break; } - attr = find_attr (XSTR (exp, 0), 0); - if (! attr) - abort (); + attr = find_attr (&XSTR (exp, 0), 0); + gcc_assert (attr); /* Now is the time to expand the value of a constant attribute. */ if (attr->is_const) @@ -4549,10 +3488,6 @@ write_test_expr (rtx exp, int flags) XSTR (exp, 1), XINT (exp, 0), GET_MODE_NAME (GET_MODE (exp))); break; - case MATCH_INSN: - printf ("%s (insn)", XSTR (exp, 0)); - break; - /* Constant integer. */ case CONST_INT: printf (HOST_WIDE_INT_PRINT_DEC, XWINT (exp, 0)); @@ -4560,7 +3495,7 @@ write_test_expr (rtx exp, int flags) /* A random C expression. */ case SYMBOL_REF: - printf ("%s", XSTR (exp, 0)); + print_c_condition (XSTR (exp, 0)); break; /* The address of the branch target. */ @@ -4710,10 +3645,14 @@ walk_attr_value (rtx exp) must_extract = 1; return; + case EQ_ATTR_ALT: + must_extract = must_constrain = 1; + break; + case EQ_ATTR: if (XSTR (exp, 0) == alternative_name) must_extract = must_constrain = 1; - else if (strcmp (XSTR (exp, 0), "length") == 0) + else if (strcmp_check (XSTR (exp, 0), length_str) == 0) length_used = 1; return; @@ -4766,8 +3705,6 @@ write_attr_get (struct attr_desc *attr) printf ("static "); if (!attr->is_numeric) printf ("enum attr_%s\n", attr->name); - else if (attr->unsigned_p) - printf ("unsigned int\n"); else printf ("int\n"); @@ -4785,45 +3722,23 @@ write_attr_get (struct attr_desc *attr) for (av = attr->first_value; av; av = av->next) if (av->num_insns != 0) write_attr_set (attr, 2, av->value, "return", ";", - true_rtx, av->first_insn->insn_code, - av->first_insn->insn_index); + true_rtx, av->first_insn->def->insn_code, + av->first_insn->def->insn_index); printf ("}\n\n"); return; } printf ("{\n"); + printf (" switch (recog_memoized (insn))\n"); + printf (" {\n"); - if (GET_CODE (common_av->value) == FFS) - { - rtx p = XEXP (common_av->value, 0); - - /* No need to emit code to abort if the insn is unrecognized; the - other get_attr_foo functions will do that when we call them. */ - - write_toplevel_expr (p); - - printf ("\n if (accum && accum == (accum & -accum))\n"); - printf (" {\n"); - printf (" int i;\n"); - printf (" for (i = 0; accum >>= 1; ++i) continue;\n"); - printf (" accum = i;\n"); - printf (" }\n else\n"); - printf (" accum = ~accum;\n"); - printf (" return accum;\n}\n\n"); - } - else - { - printf (" switch (recog_memoized (insn))\n"); - printf (" {\n"); - - for (av = attr->first_value; av; av = av->next) - if (av != common_av) - write_attr_case (attr, av, 1, "return", ";", 4, true_rtx); + for (av = attr->first_value; av; av = av->next) + if (av != common_av) + write_attr_case (attr, av, 1, "return", ";", 4, true_rtx); - write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx); - printf (" }\n}\n\n"); - } + write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx); + printf (" }\n}\n\n"); } /* Given an AND tree of known true terms (because we are inside an `if' with @@ -4946,6 +3861,25 @@ write_attr_set (struct attr_desc *attr, int indent, rtx value, } } +/* Write a series of case statements for every instruction in list IE. + INDENT is the amount of indentation to write before each case. */ + +static void +write_insn_cases (struct insn_ent *ie, int indent) +{ + for (; ie != 0; ie = ie->next) + if (ie->def->insn_code != -1) + { + write_indent (indent); + if (GET_CODE (ie->def->def) == DEFINE_PEEPHOLE) + printf ("case %d: /* define_peephole, line %d */\n", + ie->def->insn_code, ie->def->lineno); + else + printf ("case %d: /* %s */\n", + ie->def->insn_code, XSTR (ie->def->def, 0)); + } +} + /* Write out the computation for one attribute value. */ static void @@ -4953,8 +3887,6 @@ write_attr_case (struct attr_desc *attr, struct attr_value *av, int write_case_lines, const char *prefix, const char *suffix, int indent, rtx known_true) { - struct insn_ent *ie; - if (av->num_insns == 0) return; @@ -4971,14 +3903,7 @@ write_attr_case (struct attr_desc *attr, struct attr_value *av, } if (write_case_lines) - { - for (ie = av->first_insn; ie; ie = ie->next) - if (ie->insn_code != -1) - { - write_indent (indent); - printf ("case %d:\n", ie->insn_code); - } - } + write_insn_cases (av->first_insn, indent); else { write_indent (indent); @@ -5001,8 +3926,8 @@ write_attr_case (struct attr_desc *attr, struct attr_value *av, } write_attr_set (attr, indent + 2, av->value, prefix, suffix, - known_true, av->first_insn->insn_code, - av->first_insn->insn_index); + known_true, av->first_insn->def->insn_code, + av->first_insn->def->insn_index); if (strncmp (prefix, "return", 6)) { @@ -5027,8 +3952,6 @@ write_expr_attr_cache (rtx p, struct attr_desc *attr) if (!attr->is_numeric) printf (" enum attr_%s ", attr->name); - else if (attr->unsigned_p) - printf (" unsigned int "); else printf (" int "); @@ -5059,56 +3982,7 @@ write_expr_attr_cache (rtx p, struct attr_desc *attr) return 0; } -/* Evaluate an expression at top level. A front end to write_test_expr, - in which we cache attribute values and break up excessively large - expressions to cater to older compilers. */ - -static void -write_toplevel_expr (rtx p) -{ - struct attr_desc *attr; - int i; - - for (i = 0; i < MAX_ATTRS_INDEX; ++i) - for (attr = attrs[i]; attr; attr = attr->next) - if (!attr->is_const) - write_expr_attr_cache (p, attr); - - printf (" unsigned long accum = 0;\n\n"); - - while (GET_CODE (p) == IOR) - { - rtx e; - if (GET_CODE (XEXP (p, 0)) == IOR) - e = XEXP (p, 1), p = XEXP (p, 0); - else - e = XEXP (p, 0), p = XEXP (p, 1); - - printf (" accum |= "); - write_test_expr (e, 3); - printf (";\n"); - } - printf (" accum |= "); - write_test_expr (p, 3); - printf (";\n"); -} - -/* Utilities to write names in various forms. */ - -static void -write_unit_name (const char *prefix, int num, const char *suffix) -{ - struct function_unit *unit; - - for (unit = units; unit; unit = unit->next) - if (unit->num == num) - { - printf ("%s%s%s", prefix, unit->name, suffix); - return; - } - - printf ("%s%s", prefix, suffix); -} +/* Utilities to write in various forms. */ static void write_attr_valueq (struct attr_desc *attr, const char *s) @@ -5119,32 +3993,7 @@ write_attr_valueq (struct attr_desc *attr, const char *s) printf ("%d", num); - /* Make the blockage range values and function units used values easier - to read. */ - if (attr->func_units_p) - { - if (num == -1) - printf (" /* units: none */"); - else if (num >= 0) - write_unit_name (" /* units: ", num, " */"); - else - { - int i; - const char *sep = " /* units: "; - for (i = 0, num = ~num; num; i++, num >>= 1) - if (num & 1) - { - write_unit_name (sep, i, (num == 1) ? " */" : ""); - sep = ", "; - } - } - } - - else if (attr->blockage_p) - printf (" /* min %d, max %d */", num >> (HOST_BITS_PER_INT / 2), - num & ((1 << (HOST_BITS_PER_INT / 2)) - 1)); - - else if (num > 9 || num < 0) + if (num > 9 || num < 0) printf (" /* 0x%x */", num); } else @@ -5171,12 +4020,12 @@ write_attr_value (struct attr_desc *attr, rtx value) break; case SYMBOL_REF: - fputs (XSTR (value, 0), stdout); + print_c_condition (XSTR (value, 0)); break; case ATTR: { - struct attr_desc *attr2 = find_attr (XSTR (value, 0), 0); + struct attr_desc *attr2 = find_attr (&XSTR (value, 0), 0); printf ("get_attr_%s (%s)", attr2->name, (attr2->is_const ? "" : "insn")); } @@ -5207,7 +4056,7 @@ write_attr_value (struct attr_desc *attr, rtx value) break; default: - abort (); + gcc_unreachable (); } } @@ -5250,6 +4099,7 @@ write_eligible_delay (const char *kind) struct delay_desc *delay; int max_slots; char str[50]; + const char *pstr; struct attr_desc *attr; struct attr_value *av, *common_av; int i; @@ -5270,17 +4120,20 @@ write_eligible_delay (const char *kind) printf ("{\n"); printf (" rtx insn;\n"); printf ("\n"); - printf (" if (slot >= %d)\n", max_slots); - printf (" abort ();\n"); + printf (" gcc_assert (slot < %d);\n", max_slots); + printf ("\n"); + /* Allow dbr_schedule to pass labels, etc. This can happen if try_split + converts a compound instruction into a loop. */ + printf (" if (!INSN_P (candidate_insn))\n"); + printf (" return 0;\n"); printf ("\n"); /* If more than one delay type, find out which type the delay insn is. */ if (num_delays > 1) { - attr = find_attr ("*delay_type", 0); - if (! attr) - abort (); + attr = find_attr (&delay_type_str, 0); + gcc_assert (attr); common_av = find_most_used (attr); printf (" insn = delay_insn;\n"); @@ -5296,8 +4149,7 @@ write_eligible_delay (const char *kind) printf (" }\n\n"); /* Ensure matched. Otherwise, shouldn't have been called. */ - printf (" if (slot < %d)\n", max_slots); - printf (" abort ();\n\n"); + printf (" gcc_assert (slot >= %d);\n\n", max_slots); } /* If just one type of delay slot, write simple switch. */ @@ -5307,9 +4159,8 @@ write_eligible_delay (const char *kind) printf (" switch (recog_memoized (insn))\n"); printf (" {\n"); - attr = find_attr ("*delay_1_0", 0); - if (! attr) - abort (); + attr = find_attr (&delay_1_0_str, 0); + gcc_assert (attr); common_av = find_most_used (attr); for (av = attr->first_value; av; av = av->next) @@ -5337,9 +4188,9 @@ write_eligible_delay (const char *kind) printf ("\t{\n"); sprintf (str, "*%s_%d_%d", kind, delay->num, i / 3); - attr = find_attr (str, 0); - if (! attr) - abort (); + pstr = str; + attr = find_attr (&pstr, 0); + gcc_assert (attr); common_av = find_most_used (attr); for (av = attr->first_value; av; av = av->next) @@ -5351,179 +4202,13 @@ write_eligible_delay (const char *kind) } printf (" default:\n"); - printf (" abort ();\n"); + printf (" gcc_unreachable ();\n"); printf (" }\n"); } printf ("}\n\n"); } -/* Write routines to compute conflict cost for function units. Then write a - table describing the available function units. */ - -static void -write_function_unit_info (void) -{ - struct function_unit *unit; - int i; - - /* Write out conflict routines for function units. Don't bother writing - one if there is only one issue delay value. */ - - for (unit = units; unit; unit = unit->next) - { - if (unit->needs_blockage_function) - write_complex_function (unit, "blockage", "block"); - - /* If the minimum and maximum conflict costs are the same, there - is only one value, so we don't need a function. */ - if (! unit->needs_conflict_function) - { - unit->default_cost = make_numeric_value (unit->issue_delay.max); - continue; - } - - /* The function first computes the case from the candidate insn. */ - unit->default_cost = make_numeric_value (0); - write_complex_function (unit, "conflict_cost", "cost"); - } - - /* Now that all functions have been written, write the table describing - the function units. The name is included for documentation purposes - only. */ - - printf ("const struct function_unit_desc function_units[] = {\n"); - - /* Write out the descriptions in numeric order, but don't force that order - on the list. Doing so increases the runtime of genattrtab.c. */ - for (i = 0; i < num_units; i++) - { - for (unit = units; unit; unit = unit->next) - if (unit->num == i) - break; - - printf (" {\"%s\", %d, %d, %d, %s, %d, %s_unit_ready_cost, ", - unit->name, 1 << unit->num, unit->multiplicity, - unit->simultaneity, XSTR (unit->default_cost, 0), - unit->issue_delay.max, unit->name); - - if (unit->needs_conflict_function) - printf ("%s_unit_conflict_cost, ", unit->name); - else - printf ("0, "); - - printf ("%d, ", unit->max_blockage); - - if (unit->needs_range_function) - printf ("%s_unit_blockage_range, ", unit->name); - else - printf ("0, "); - - if (unit->needs_blockage_function) - printf ("%s_unit_blockage", unit->name); - else - printf ("0"); - - printf ("}, \n"); - } - - if (num_units == 0) - printf ("{\"dummy\", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* a dummy element */"); - printf ("};\n\n"); -} - -static void -write_complex_function (struct function_unit *unit, - const char *name, - const char *connection) -{ - struct attr_desc *case_attr, *attr; - struct attr_value *av, *common_av; - rtx value; - char str[256]; - int using_case; - int i; - - printf ("static int\n"); - printf ("%s_unit_%s (rtx executing_insn, rtx candidate_insn)\n", - unit->name, name); - printf ("{\n"); - printf (" rtx insn;\n"); - printf (" int casenum;\n\n"); - printf (" insn = executing_insn;\n"); - printf (" switch (recog_memoized (insn))\n"); - printf (" {\n"); - - /* Write the `switch' statement to get the case value. */ - if (strlen (unit->name) + sizeof "*_cases" > 256) - abort (); - sprintf (str, "*%s_cases", unit->name); - case_attr = find_attr (str, 0); - if (! case_attr) - abort (); - common_av = find_most_used (case_attr); - - for (av = case_attr->first_value; av; av = av->next) - if (av != common_av) - write_attr_case (case_attr, av, 1, - "casenum =", ";", 4, unit->condexp); - - write_attr_case (case_attr, common_av, 0, - "casenum =", ";", 4, unit->condexp); - printf (" }\n\n"); - - /* Now write an outer switch statement on each case. Then write - the tests on the executing function within each. */ - printf (" insn = candidate_insn;\n"); - printf (" switch (casenum)\n"); - printf (" {\n"); - - for (i = 0; i < unit->num_opclasses; i++) - { - /* Ensure using this case. */ - using_case = 0; - for (av = case_attr->first_value; av; av = av->next) - if (av->num_insns - && contained_in_p (make_numeric_value (i), av->value)) - using_case = 1; - - if (! using_case) - continue; - - printf (" case %d:\n", i); - sprintf (str, "*%s_%s_%d", unit->name, connection, i); - attr = find_attr (str, 0); - if (! attr) - abort (); - - /* If single value, just write it. */ - value = find_single_value (attr); - if (value) - write_attr_set (attr, 6, value, "return", ";\n", true_rtx, -2, -2); - else - { - common_av = find_most_used (attr); - printf (" switch (recog_memoized (insn))\n"); - printf ("\t{\n"); - - for (av = attr->first_value; av; av = av->next) - if (av != common_av) - write_attr_case (attr, av, 1, - "return", ";", 8, unit->condexp); - - write_attr_case (attr, common_av, 0, - "return", ";", 8, unit->condexp); - printf (" }\n\n"); - } - } - - /* This default case should not be needed, but gcc's analysis is not - good enough to realize that the default case is not needed for the - second switch statement. */ - printf (" default:\n abort ();\n"); - printf (" }\n}\n\n"); -} - /* This page contains miscellaneous utility routines. */ /* Given a pointer to a (char *), return a malloc'ed string containing the @@ -5544,13 +4229,15 @@ next_comma_elt (const char **pstr) } /* Return a `struct attr_desc' pointer for a given named attribute. If CREATE - is nonzero, build a new attribute, if one does not exist. */ + is nonzero, build a new attribute, if one does not exist. *NAME_P is + replaced by a pointer to a canonical copy of the string. */ static struct attr_desc * -find_attr (const char *name, int create) +find_attr (const char **name_p, int create) { struct attr_desc *attr; int index; + const char *name = *name_p; /* Before we resort to using `strcmp', see if the string address matches anywhere. In most cases, it should have been canonicalized to do so. */ @@ -5565,19 +4252,24 @@ find_attr (const char *name, int create) /* Otherwise, do it the slow way. */ for (attr = attrs[index]; attr; attr = attr->next) if (name[0] == attr->name[0] && ! strcmp (name, attr->name)) - return attr; + { + *name_p = attr->name; + return attr; + } if (! create) return NULL; attr = oballoc (sizeof (struct attr_desc)); - attr->name = attr_string (name, strlen (name)); + attr->name = DEF_ATTR_STRING (name); attr->first_value = attr->default_val = NULL; - attr->is_numeric = attr->negative_ok = attr->is_const = attr->is_special = 0; - attr->unsigned_p = attr->func_units_p = attr->blockage_p = attr->static_p = 0; + attr->is_numeric = attr->is_const = attr->is_special = 0; + attr->static_p = 0; attr->next = attrs[index]; attrs[index] = attr; + *name_p = attr->name; + return attr; } @@ -5588,17 +4280,12 @@ make_internal_attr (const char *name, rtx value, int special) { struct attr_desc *attr; - attr = find_attr (name, 1); - if (attr->default_val) - abort (); + attr = find_attr (&name, 1); + gcc_assert (!attr->default_val); attr->is_numeric = 1; attr->is_const = 0; attr->is_special = (special & ATTR_SPECIAL) != 0; - attr->negative_ok = (special & ATTR_NEGATIVE_OK) != 0; - attr->unsigned_p = (special & ATTR_UNSIGNED) != 0; - attr->func_units_p = (special & ATTR_FUNC_UNITS) != 0; - attr->blockage_p = (special & ATTR_BLOCKAGE) != 0; attr->static_p = (special & ATTR_STATIC) != 0; attr->default_val = get_attr_value (value, attr, -2); } @@ -5622,28 +4309,6 @@ find_most_used (struct attr_desc *attr) return most_used; } -/* If an attribute only has a single value used, return it. Otherwise - return NULL. */ - -static rtx -find_single_value (struct attr_desc *attr) -{ - struct attr_value *av; - rtx unique_value; - - unique_value = NULL; - for (av = attr->first_value; av; av = av->next) - if (av->num_insns) - { - if (unique_value) - return NULL; - else - unique_value = av->value; - } - - return unique_value; -} - /* Return (attr_value "n") */ rtx @@ -5653,8 +4318,7 @@ make_numeric_value (int n) rtx exp; char *p; - if (n < 0) - abort (); + gcc_assert (n >= 0); if (n < 20 && int_values[n]) return int_values[n]; @@ -5668,15 +4332,6 @@ make_numeric_value (int n) return exp; } -static void -extend_range (struct range *range, int min, int max) -{ - if (range->min > min) - range->min = min; - if (range->max < max) - range->max = max; -} - static rtx copy_rtx_unchanging (rtx orig) { @@ -5693,9 +4348,8 @@ copy_rtx_unchanging (rtx orig) static void write_const_num_delay_slots (void) { - struct attr_desc *attr = find_attr ("*num_delay_slots", 0); + struct attr_desc *attr = find_attr (&num_delay_slots_str, 0); struct attr_value *av; - struct insn_ent *ie; if (attr) { @@ -5709,12 +4363,7 @@ write_const_num_delay_slots (void) length_used = 0; walk_attr_value (av->value); if (length_used) - { - for (ie = av->first_insn; ie; ie = ie->next) - if (ie->insn_code != -1) - printf (" case %d:\n", ie->insn_code); - printf (" return 0;\n"); - } + write_insn_cases (av->first_insn, 4); } printf (" default:\n"); @@ -5734,9 +4383,6 @@ main (int argc, char **argv) progname = "genattrtab"; - if (argc <= 1) - fatal ("no input file name"); - if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE) return (FATAL_EXIT_CODE); @@ -5751,7 +4397,11 @@ main (int argc, char **argv) ATTR_IND_SIMPLIFIED_P (true_rtx) = ATTR_IND_SIMPLIFIED_P (false_rtx) = 1; ATTR_PERMANENT_P (true_rtx) = ATTR_PERMANENT_P (false_rtx) = 1; - alternative_name = attr_string ("alternative", strlen ("alternative")); + alternative_name = DEF_ATTR_STRING ("alternative"); + length_str = DEF_ATTR_STRING ("length"); + delay_type_str = DEF_ATTR_STRING ("*delay_type"); + delay_1_0_str = DEF_ATTR_STRING ("*delay_1_0"); + num_delay_slots_str = DEF_ATTR_STRING ("*num_delay_slots"); printf ("/* Generated automatically by the program `genattrtab'\n\ from the machine description file `md'. */\n\n"); @@ -5783,10 +4433,6 @@ from the machine description file `md'. */\n\n"); gen_delay (desc, lineno); break; - case DEFINE_FUNCTION_UNIT: - gen_unit (desc, lineno); - break; - case DEFINE_CPU_UNIT: gen_cpu_unit (desc); break; @@ -5859,14 +4505,10 @@ from the machine description file `md'. */\n\n"); if (num_delays) expand_delays (); - if (num_units || num_dfa_decls) - { - /* Expand DEFINE_FUNCTION_UNIT information into new attributes. */ - expand_units (); - /* Build DFA, output some functions and expand DFA information - into new attributes. */ - expand_automata (); - } + /* Build DFA, output some functions and expand DFA information + to new attributes. */ + if (num_dfa_decls) + expand_automata (); printf ("#include \"config.h\"\n"); printf ("#include \"system.h\"\n"); @@ -5922,8 +4564,7 @@ from the machine description file `md'. */\n\n"); optimize_attrs (); /* Now write out all the `gen_attr_...' routines. Do these before the - special routines (specifically before write_function_unit_info), so - that they get defined before they are used. */ + special routines so that they get defined before they are used. */ for (i = 0; i < MAX_ATTRS_INDEX; i++) for (attr = attrs[i]; attr; attr = attr->next) @@ -5934,7 +4575,7 @@ from the machine description file `md'. */\n\n"); insn_alts_p = (attr->name [0] == '*' - && strcmp (&attr->name [1], INSN_ALTS_FUNC_NAME) == 0); + && strcmp (&attr->name[1], INSN_ALTS_FUNC_NAME) == 0); if (insn_alts_p) printf ("\n#if AUTOMATON_ALTS\n"); write_attr_get (attr); @@ -5955,14 +4596,10 @@ from the machine description file `md'. */\n\n"); write_eligible_delay ("annul_false"); } - if (num_units || num_dfa_decls) - { - /* Write out information about function units. */ - write_function_unit_info (); - /* Output code for pipeline hazards recognition based on DFA - (deterministic finite state automata. */ - write_automata (); - } + /* Output code for pipeline hazards recognition based on DFA + (deterministic finite-state automata). */ + if (num_dfa_decls) + write_automata (); /* Write out constant delay slot info. */ write_const_num_delay_slots ();