(struct attr_desc): Add unsigned_p field.

(struct function_unit_op): Add issue_delay, conflict_exp, and
	issue_exp fields.  Drop busyexp field.
	(struct function_unit): Add needs_blockage_function,
	needs_range_function, issue_delay, and max_blockage fields.  Drop
	costexp, and busy delay fields.
	(enum operator): Add POS_MINUS_OP, EQ_OP, MIN_OP, RANGE_OP.
	(operate_exp): Implement new ops.
	(make_internal_attr): Set unsigned_p based on the value of SPECIAL.
	(write_attr_get): Function is unsigned when unsigned_p is true.
	(write_attr_valueq): Write hex value of large constants in a comment.
	(simplify_by_exploding): Check for EXP having no EQ_ATTR expressions
	and for all values as the default.
	(find_and_mark_used_attributes): Add TERMS and NTERMS parameters.
	(max_attr_value): Allow IF_THEN_ELSE.
	(simplify_knowing, write_complex_function, extend_range): New
	functions.
	(gen_unit): Use local variables to name the fields.  Change the
	meaning of busy-delay to issue-delay.
	(expand_units): Compute issue_exp.  Write attributes for computing
	`<name>_unit_blockage' and `<name>_unit_blockage_range' functions.
	Compute max_blockage, and the needs_*_function values.
	(write_function_unit_info): Write blockage function and conflict cost
	functions using write_complex_function.  Write new function_unit_desc
	fields.
(expand_units): Use the normalized values of the
	unit's CONDEXP and BUSYEXP.

From-SVN: r1952
This commit is contained in:
Tom Wood 1992-08-25 20:26:02 +00:00
parent de19227a25
commit bee757e1c0

View File

@ -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;