aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/genattrtab.c546
1 files changed, 400 insertions, 146 deletions
diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c
index cb22fb9..2eb9230 100644
--- a/gcc/genattrtab.c
+++ b/gcc/genattrtab.c
@@ -167,6 +167,7 @@ struct attr_desc
struct attr_desc *next; /* Next attribute. */
int is_numeric; /* Values of this attribute are numeric. */
int negative_ok; /* Allow negative numeric values. */
+ int unsigned_p; /* Make the output function unsigned int. */
int is_const; /* Attribute value constant for each run. */
int is_special; /* Don't call `write_attr_set'. */
struct attr_value *first_value; /* First value of this attribute. */
@@ -175,6 +176,14 @@ struct attr_desc
#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
@@ -192,7 +201,9 @@ struct function_unit_op
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. */
- rtx busyexp; /* Expression computing conflict cost. */
+ 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. */
};
/* Record information about each function unit mentioned in a
@@ -207,14 +218,14 @@ struct function_unit
int simultaneity; /* Maximum number of simultaneous insns
on this function unit or 0 if unlimited. */
rtx condexp; /* Expression TRUE for insn needing unit. */
- rtx costexp; /* Worst-case cost as function of insn. */
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 a blockage range function required. */
rtx default_cost; /* Conflict cost, if constant. */
- rtx max_busy_cost; /* Maximum conflict cost. */
- int min_busy_delay; /* Minimum conflict cost. */
- int max_busy_delay; /* Maximum conflict cost. */
+ struct range issue_delay; /* Range of issue delay values. */
+ int max_blockage; /* Maximum time an insn blocks the unit. */
};
/* Listheads of above structures. */
@@ -240,7 +251,7 @@ static int num_units;
/* Used as operand to `operate_exp': */
-enum operator {PLUS_OP, MINUS_OP, OR_OP, MAX_OP};
+enum operator {PLUS_OP, MINUS_OP, POS_MINUS_OP, EQ_OP, OR_OP, MAX_OP, MIN_OP, RANGE_OP};
/* Stores, for each insn code, the number of constraint alternatives. */
@@ -301,6 +312,7 @@ static rtx copy_boolean ();
static void expand_delays ();
static rtx operate_exp ();
static void expand_units ();
+static rtx simplify_knowing ();
static rtx encode_units_mask ();
static void fill_attr ();
static rtx substitute_address ();
@@ -349,6 +361,7 @@ static void write_upcase ();
static void write_indent ();
static void write_eligible_delay ();
static void write_function_unit_info ();
+static void write_complex_function ();
static int n_comma_elts ();
static char *next_comma_elt ();
static struct attr_desc *find_attr ();
@@ -356,6 +369,7 @@ static void make_internal_attr ();
static struct attr_value *find_most_used ();
static rtx find_single_value ();
static rtx make_numeric_value ();
+static void extend_range ();
char *xrealloc ();
char *xmalloc ();
static void fatal ();
@@ -1504,10 +1518,25 @@ operate_exp (op, left, right)
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:
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;
@@ -1515,6 +1544,13 @@ operate_exp (op, left, right)
i = right_value;
break;
+ case MIN_OP:
+ if (left_value < right_value)
+ i = left_value;
+ else
+ i = right_value;
+ break;
+
default:
abort ();
}
@@ -1646,7 +1682,15 @@ operate_exp (op, left, right)
and a `<name>_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). */
+ can start (ignore limitations on the number of simultaneous insns).
+
+ For each unit, a `<name>_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
+ `<name>_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 ()
@@ -1659,19 +1703,47 @@ expand_units ()
char *str;
int i, j, u, num, nvalues;
- /* Validate the expressions we were given for the conditions and busy cost.
- Then make attributes for use in the conflict function. */
+ /* 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)
- for (op = unit->ops; op; op = op->next)
- {
- op->condexp = check_attr_test (op->condexp, 0);
- op->busyexp = check_attr_value (make_canonical (NULL_ATTR,
- op->busyexp),
+ {
+ rtx min_issue = make_numeric_value (unit->issue_delay.min);
+
+ unit->condexp = check_attr_test (unit->condexp, 0);
+
+ 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);
- str = attr_printf (strlen (unit->name) + 11, "*%s_case_%d",
- unit->name, op->num);
- make_internal_attr (str, op->busyexp, 1);
- }
+ 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) + 11, "*%s_cost_%d",
+ unit->name, op->num);
+ make_internal_attr (str, issue_exp, 1);
+ }
+
+ /* Validate the condition. */
+ op->condexp = check_attr_test (op->condexp, 0);
+ }
+ }
/* Compute the mask of function units used. Initially, the unitsmask is
zero. Set up a conditional to compute each unit's contribution. */
@@ -1682,7 +1754,7 @@ expand_units ()
/* Merge each function unit into the unit mask attributes. */
for (unit = units; unit; unit = unit->next)
{
- XEXP (newexp, 0) = check_attr_test (unit->condexp, 0);
+ XEXP (newexp, 0) = unit->condexp;
XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
unitsmask = operate_exp (OR_OP, unitsmask, newexp);
}
@@ -1788,13 +1860,128 @@ expand_units ()
XVECEXP (readycost, 0, nvalues * 2 + 1) = make_numeric_value (value);
}
- /* Make an attribute for the ready_cost function. Simplifying
- further with simplify_by_exploding doesn't win. */
if (u < num_units)
- str = attr_printf (strlen (unit->name) + 20, "*%s_unit_ready_cost",
- unit->name);
+ {
+ rtx max_blockage = 0, min_blockage = 0;
+
+ /* Simplify the readycost expression by only considering insns
+ that use the unit. */
+ readycost = simplify_knowing (readycost, unit->condexp);
+
+ /* 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.
+
+ The issue delay function for C is op->issue_exp and is used to
+ write the `<name>_unit_conflict_cost' function. Symbolicly
+ this is "ISSUE-DELAY (E,C)".
+
+ The pipeline delay results form the FIFO constraint on the
+ function unit and is "READY-COST (E) + 1 - READY-COST (C)".
+
+ 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 non-zero and zero otherwise.
+
+ Thus, BLOCKAGE (E,C) when SIMULTANEITY is zero is
+
+ MAX (ISSUE-DELAY (E,C),
+ READY-COST (E) - (READY-COST (C) - 1))
+
+ and otherwise
+
+ MAX (ISSUE-DELAY (E,C),
+ READY-COST (E) - (READY-COST (C) - 1),
+ READY-COST (E) - FILL-TIME)
+
+ The `<name>_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
+ `<name>_unit_blockage_range'. Finally, the maximum blockage
+ cost, MAX (BLOCKAGE (*,*)), is computed. */
+
+ for (op = unit->ops; op; op = op->next)
+ {
+ rtx blockage = readycost;
+ int delay = op->ready - 1;
+
+ if (unit->simultaneity != 0)
+ delay = MIN (delay, ((unit->simultaneity - 1)
+ * unit->issue_delay.min));
+
+ if (delay > 0)
+ blockage = operate_exp (POS_MINUS_OP, blockage,
+ make_numeric_value (delay));
+
+ blockage = operate_exp (MAX_OP, blockage, op->issue_exp);
+ blockage = simplify_knowing (blockage, unit->condexp);
+
+ /* 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);
+ }
+
+ /* Make an attribute for use in the blockage function. */
+ str = attr_printf (strlen (unit->name) + 12, "*%s_block_%d",
+ unit->name, op->num);
+ make_internal_attr (str, blockage, 1);
+ }
+
+ /* Record MAX (BLOCKAGE (*,*)). */
+ unit->max_blockage = max_attr_value (max_blockage);
+
+ /* 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 it's value. */
+ newexp = operate_exp (RANGE_OP, min_blockage, max_blockage);
+ newexp = simplify_knowing (newexp, unit->condexp);
+
+ str = attr_printf (strlen (unit->name) + 20,
+ "*%s_unit_blockage_range", unit->name);
+ make_internal_attr (str, newexp, 4);
+ }
+
+ str = attr_printf (strlen (unit->name) + 20, "*%s_unit_ready_cost",
+ unit->name);
+ }
else
str = "*result_ready_cost";
+
+ /* Make an attribute for the ready_cost function. Simplifying
+ further with simplify_by_exploding doesn't win. */
make_internal_attr (str, readycost, 0);
}
@@ -1804,7 +1991,8 @@ expand_units ()
{
rtx caseexp;
- if (unit->min_busy_delay == unit->max_busy_delay)
+ if (! unit->needs_conflict_function
+ && ! unit->needs_blockage_function)
continue;
caseexp = rtx_alloc (COND);
@@ -1833,6 +2021,21 @@ expand_units ()
}
}
+/* Simplify EXP given KNOWN_TRUE. */
+
+static rtx
+simplify_knowing (exp, known_true)
+ rtx exp, known_true;
+{
+ if (GET_CODE (exp) != CONST_STRING)
+ {
+ exp = attr_rtx (IF_THEN_ELSE, known_true, exp,
+ make_numeric_value (max_attr_value (exp)));
+ exp = simplify_by_exploding (exp);
+ }
+ return exp;
+}
+
/* 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
@@ -3170,11 +3373,11 @@ simplify_by_exploding (exp)
rtx list = 0, link, condexp, defval;
struct dimension *space;
rtx *condtest, *condval;
- int i, j, total, ndim;
+ int i, j, total, ndim = 0;
int most_tests, num_marks, new_marks;
/* Locate all the EQ_ATTR expressions. */
- if (! find_and_mark_used_attributes (exp, &list))
+ if (! find_and_mark_used_attributes (exp, &list, &ndim) || ndim == 0)
{
unmark_used_attributes (list, 0, 0);
return exp;
@@ -3186,9 +3389,6 @@ simplify_by_exploding (exp)
cover the domain of the attribute. This makes the expanded COND form
order independent. */
- ndim = 0;
- for (link = list; link; link = XEXP (link, 1))
- ndim++;
space = (struct dimension *) alloca (ndim * sizeof (struct dimension));
total = 1;
@@ -3289,6 +3489,10 @@ simplify_by_exploding (exp)
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.) */
@@ -3311,8 +3515,9 @@ simplify_by_exploding (exp)
tests have known value. */
static int
-find_and_mark_used_attributes (exp, terms)
+find_and_mark_used_attributes (exp, terms, nterms)
rtx exp, *terms;
+ int *nterms;
{
int i;
@@ -3325,28 +3530,29 @@ find_and_mark_used_attributes (exp, terms)
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))
+ 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))
+ 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))
+ 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))
+ if (! find_and_mark_used_attributes (XVECEXP (exp, 0, i), terms, nterms))
return 0;
- if (! find_and_mark_used_attributes (XEXP (exp, 1), terms))
+ if (! find_and_mark_used_attributes (XEXP (exp, 1), terms, nterms))
return 0;
return 1;
}
@@ -3935,15 +4141,21 @@ gen_unit (def)
{
struct function_unit *unit;
struct function_unit_op *op;
+ 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, XSTR (def, 0)))
+ if (! strcmp (unit->name, name))
{
- if (unit->multiplicity != XINT (def, 1)
- || unit->simultaneity != XINT (def, 2))
+ if (unit->multiplicity != multiplicity
+ || unit->simultaneity != simultaneity)
fatal ("Differing specifications given for `%s' function unit.",
unit->name);
break;
@@ -3952,27 +4164,28 @@ gen_unit (def)
if (unit == 0)
{
unit = (struct function_unit *) xmalloc (sizeof (struct function_unit));
- unit->name = XSTR (def, 0);
- unit->multiplicity = XINT (def, 1);
- unit->simultaneity = XINT (def, 2);
+ 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->min_busy_delay = unit->max_busy_delay = XINT (def, 5);
units = unit;
}
/* Make a new operation class structure entry and initialize it. */
op = (struct function_unit_op *) xmalloc (sizeof (struct function_unit_op));
- op->condexp = XEXP (def, 3);
+ op->condexp = condexp;
op->num = unit->num_opclasses++;
- op->ready = XINT (def, 4);
+ op->ready = ready_cost;
+ op->issue_delay = issue_delay;
op->next = unit->ops;
unit->ops = op;
- /* Set our busy expression based on whether or not an optional conflict
+ /* Set our issue expression based on whether or not an optional conflict
vector was specified. */
if (XVEC (def, 6))
{
@@ -3983,17 +4196,13 @@ gen_unit (def)
for (i = 0; i < XVECLEN (def, 6); i++)
orexp = insert_right_side (IOR, orexp, XVECEXP (def, 6, i), -2);
- op->busyexp = attr_rtx (IF_THEN_ELSE, orexp,
- make_numeric_value (XINT (def, 5)),
- make_numeric_value (0));
- unit->min_busy_delay = MIN (unit->min_busy_delay, 0);
- unit->max_busy_delay = MAX (unit->max_busy_delay, XINT (def, 5));
+ op->conflict_exp = orexp;
+ extend_range (&unit->issue_delay, 1, issue_delay);
}
else
{
- op->busyexp = make_numeric_value (XINT (def, 5));
- unit->min_busy_delay = MIN (unit->min_busy_delay, XINT (def, 5));
- unit->max_busy_delay = MAX (unit->max_busy_delay, XINT (def, 5));
+ 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
@@ -4249,6 +4458,14 @@ max_attr_value (exp)
current_max = n;
}
+ else if (GET_CODE (exp) == IF_THEN_ELSE)
+ {
+ current_max = max_attr_value (XEXP (exp, 1));
+ n = max_attr_value (XEXP (exp, 2));
+ if (n > current_max)
+ current_max = n;
+ }
+
else
abort ();
@@ -4331,10 +4548,12 @@ write_attr_get (attr)
/* Write out start of function, then all values with explicit `case' lines,
then a `default', then the value with the most uses. */
- if (attr->is_numeric)
- printf ("int\n");
- else
+ if (!attr->is_numeric)
printf ("enum attr_%s\n", attr->name);
+ else if (attr->unsigned_p)
+ printf ("unsigned int\n");
+ else
+ printf ("int\n");
/* If the attribute name starts with a star, the remainder is the name of
the subroutine to use, instead of `get_attr_...'. */
@@ -4583,7 +4802,12 @@ write_attr_valueq (attr, s)
char *s;
{
if (attr->is_numeric)
- printf ("%s", s);
+ {
+ printf ("%s", s);
+ /* Make the blockage range values easier to read. */
+ if (strlen (s) > 1)
+ printf (" /* 0x%x */", atoi (s));
+ }
else
{
write_upcase (attr->name);
@@ -4758,107 +4982,27 @@ static void
write_function_unit_info ()
{
struct function_unit *unit;
- struct attr_desc *case_attr, *attr;
- struct attr_value *av, *common_av;
- rtx value;
- char *str;
- int using_case;
int i;
/* Write out conflict routines for function units. Don't bother writing
- one if there is only one busy value. */
+ one if there is only one issue delay value. */
for (unit = units; unit; unit = unit->next)
{
- /* Record the maximum busy cost. */
- unit->max_busy_cost = make_numeric_value (unit->max_busy_delay);
+ 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->min_busy_delay == unit->max_busy_delay)
+ if (! unit->needs_conflict_function)
{
- unit->needs_conflict_function = 0;
- unit->default_cost = unit->max_busy_cost;
+ unit->default_cost = make_numeric_value (unit->issue_delay.max);
continue;
}
/* The function first computes the case from the candidate insn. */
- unit->needs_conflict_function = 1;
unit->default_cost = make_numeric_value (0);
-
- printf ("static int\n");
- printf ("%s_unit_conflict_cost (executing_insn, candidate_insn)\n",
- unit->name);
- printf (" rtx executing_insn;\n");
- printf (" rtx candidate_insn;\n");
- printf ("{\n");
- printf (" rtx insn;\n");
- printf (" int casenum;\n\n");
- printf (" insn = candidate_insn;\n");
- printf (" switch (recog_memoized (insn))\n");
- printf (" {\n");
-
- /* Write the `switch' statement to get the case value. */
- str = (char *) alloca (strlen (unit->name) + 10);
- 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 = executing_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_case_%d", unit->name, 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);
- 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");
- }
- }
-
- printf (" }\n}\n\n");
+ write_complex_function (unit, "conflict_cost", "cost");
}
/* Now that all functions have been written, write the table describing
@@ -4875,13 +5019,25 @@ write_function_unit_info ()
if (unit->num == i)
break;
- printf (" {\"%s\", %d, %d, %d, %s, %s, %s_unit_ready_cost, ",
+ 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),
- XSTR (unit->max_busy_cost, 0), unit->name);
+ unit->issue_delay.max, unit->name);
if (unit->needs_conflict_function)
- printf ("%s_unit_conflict_cost", unit->name);
+ 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");
@@ -4890,6 +5046,93 @@ write_function_unit_info ()
printf ("};\n\n");
}
+
+static void
+write_complex_function (unit, name, connection)
+ struct function_unit *unit;
+ char *name, *connection;
+{
+ struct attr_desc *case_attr, *attr;
+ struct attr_value *av, *common_av;
+ rtx value;
+ char *str;
+ int using_case;
+ int i;
+
+ printf ("static int\n");
+ printf ("%s_unit_%s (executing_insn, candidate_insn)\n",
+ unit->name, name);
+ printf (" rtx executing_insn;\n");
+ printf (" rtx candidate_insn;\n");
+ printf ("{\n");
+ printf (" rtx insn;\n");
+ printf (" int casenum;\n\n");
+ printf (" insn = candidate_insn;\n");
+ printf (" switch (recog_memoized (insn))\n");
+ printf (" {\n");
+
+ /* Write the `switch' statement to get the case value. */
+ str = (char *) alloca (strlen (unit->name) + strlen (name) + strlen (connection) + 10);
+ 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 = executing_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);
+ 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");
+ }
+ }
+
+ printf (" }\n}\n\n");
+}
/* This page contains miscellaneous utility routines. */
@@ -4996,6 +5239,7 @@ make_internal_attr (name, value, special)
attr->is_const = 0;
attr->is_special = (special & 1) != 0;
attr->negative_ok = (special & 2) != 0;
+ attr->unsigned_p = (special & 4) != 0;
attr->default_val = get_attr_value (value, attr, -2);
}
@@ -5067,6 +5311,16 @@ make_numeric_value (n)
return exp;
}
+static void
+extend_range (range, min, max)
+ struct range *range;
+ int min;
+ int max;
+{
+ if (range->min > min) range->min = min;
+ if (range->max < max) range->max = max;
+}
+
char *
xrealloc (ptr, size)
char *ptr;