+ /* Pull the first attribute value from the list and record that
+ attribute as another dimension in the attribute space. */
+ char *name = XSTR (XEXP (list, 0), 0);
+ rtx *prev;
+
+ if ((space[ndim].attr = find_attr (name, 0)) == 0
+ || space[ndim].attr->is_numeric)
+ {
+ unmark_used_attributes (list, space, ndim);
+ return exp;
+ }
+
+ /* 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);
+
+ /* 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]);
+ }
+
+ /* 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;
+ }
+
+ /* Establish the initial current value. */
+ for (i = 0; i < ndim; i++)
+ space[i].current_value = space[i].values;
+
+ condtest = (rtx *) alloca (total * sizeof (rtx));
+ condval = (rtx *) alloca (total * sizeof (rtx));
+
+ /* 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);
+
+ /* 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
+ && ! MEM_VOLATILE_P (condval[i]))
+ {
+ /* Mark the unmarked constant value and count how many are marked. */
+ MEM_VOLATILE_P (condval[i]) = 1;
+ for (j = new_marks = 0; j < total; j++)
+ if (GET_CODE (condval[j]) == CONST_STRING
+ && MEM_VOLATILE_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++)
+ MEM_VOLATILE_P (condval[i]) = 0;
+
+ /* Give up if nothing is constant. */
+ if (num_marks == 0)
+ return exp;
+
+ /* If all values are the default, use that. */
+ if (total == most_tests)
+ return defval;
+
+ /* 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.) */
+ 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++;
+ }
+
+ return condexp;
+}
+
+/* Set the MEM_VOLATILE_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. */
+
+static int
+find_and_mark_used_attributes (exp, terms, nterms)
+ rtx exp, *terms;
+ int *nterms;
+{
+ int i;
+
+ switch (GET_CODE (exp))
+ {
+ case EQ_ATTR:
+ if (! MEM_VOLATILE_P (exp))
+ {
+ rtx link = rtx_alloc (EXPR_LIST);
+ XEXP (link, 0) = exp;
+ XEXP (link, 1) = *terms;
+ *terms = link;
+ *nterms += 1;
+ MEM_VOLATILE_P (exp) = 1;
+ }
+ case CONST_STRING:
+ return 1;
+
+ 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;
+
+ 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 0;
+}
+
+/* Clear the MEM_VOLATILE_P flag in all EQ_ATTR expressions on LIST and
+ in the values of the NDIM-dimensional attribute space SPACE. */
+
+static void
+unmark_used_attributes (list, space, ndim)
+ rtx list;
+ struct dimension *space;
+ int ndim;
+{
+ rtx link, exp;
+ int i;
+
+ for (i = 0; i < ndim; i++)
+ unmark_used_attributes (space[i].values, 0, 0);
+
+ for (link = list; link; link = XEXP (link, 1))
+ {
+ exp = XEXP (link, 0);
+ if (GET_CODE (exp) == EQ_ATTR)
+ MEM_VOLATILE_P (exp) = 0;
+ }
+}
+
+/* Update the attribute dimension DIM so that all values of the attribute
+ are tested. Return the updated number of values. */
+
+static int
+add_values_to_cover (dim)
+ 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 (MEM_VOLATILE_P (exp))
+ continue;
+
+ 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;
+
+ /* 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)
+ {
+ 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;
+}
+
+/* Increment the current value for the NDIM-dimensional attribute space SPACE
+ and return FALSE if the increment overflowed. */
+
+static int
+increment_current_value (space, ndim)
+ struct dimension *space;
+ int ndim;
+{
+ int i;
+
+ 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;
+}
+
+/* Construct an expression corresponding to the current value for the
+ NDIM-dimensional attribute space SPACE. */
+
+static rtx
+test_for_current_value (space, ndim)
+ struct dimension *space;
+ int ndim;
+{
+ int i;
+ rtx exp = true_rtx;
+
+ for (i = 0; i < ndim; i++)
+ exp = insert_right_side (AND, exp, XEXP (space[i].current_value, 0),
+ -2, -2);
+
+ return exp;
+}
+
+/* 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. */
+
+static rtx
+simplify_with_current_value (exp, space, ndim)
+ rtx exp;
+ struct dimension *space;
+ int ndim;
+{
+ int i;
+ rtx x;
+
+ /* 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)
+ MEM_VOLATILE_P (x) = 0;
+ }
+
+ exp = simplify_with_current_value_aux (exp);
+
+ /* 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)
+ MEM_VOLATILE_P (x) = 1;
+ }
+
+ return exp;
+}
+
+/* Reduce the expression EXP based on the MEM_VOLATILE_P settings of
+ all EQ_ATTR expressions. */
+
+static rtx
+simplify_with_current_value_aux (exp)
+ rtx exp;
+{
+ register int i;
+ rtx cond;
+
+ switch (GET_CODE (exp))
+ {
+ case EQ_ATTR:
+ if (MEM_VOLATILE_P (exp))
+ return false_rtx;
+ else
+ return true_rtx;
+ case CONST_STRING:
+ 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);
+
+ case COND:
+ for (i = 0; i < XVECLEN (exp, 0); i += 2)
+ {
+ 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. */
+ }
+ return simplify_with_current_value_aux (XEXP (exp, 1));
+ }
+ abort ();
+}
+\f
+/* Clear the MEM_IN_STRUCT_P flag in EXP and its subexpressions. */
+
+static void
+clear_struct_flag (x)
+ rtx x;
+{
+ register int i;
+ register int j;
+ register enum rtx_code code;
+ register char *fmt;
+
+ MEM_IN_STRUCT_P (x) = 0;
+ if (RTX_UNCHANGING_P (x))
+ return;
+
+ code = GET_CODE (x);
+
+ switch (code)
+ {
+ case REG:
+ case QUEUED:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ case EQ_ATTR:
+ case ATTR_FLAG:
+ return;
+ }