Commit bee757e1 by Tom Wood

(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
parent de19227a
...@@ -167,6 +167,7 @@ struct attr_desc ...@@ -167,6 +167,7 @@ struct attr_desc
struct attr_desc *next; /* Next attribute. */ struct attr_desc *next; /* Next attribute. */
int is_numeric; /* Values of this attribute are numeric. */ int is_numeric; /* Values of this attribute are numeric. */
int negative_ok; /* Allow negative numeric values. */ 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_const; /* Attribute value constant for each run. */
int is_special; /* Don't call `write_attr_set'. */ int is_special; /* Don't call `write_attr_set'. */
struct attr_value *first_value; /* First value of this attribute. */ struct attr_value *first_value; /* First value of this attribute. */
...@@ -175,6 +176,14 @@ struct attr_desc ...@@ -175,6 +176,14 @@ struct attr_desc
#define NULL_ATTR (struct attr_desc *) NULL #define NULL_ATTR (struct attr_desc *) NULL
/* A range of values. */
struct range
{
int min;
int max;
};
/* Structure for each DEFINE_DELAY. */ /* Structure for each DEFINE_DELAY. */
struct delay_desc struct delay_desc
...@@ -192,7 +201,9 @@ struct function_unit_op ...@@ -192,7 +201,9 @@ struct function_unit_op
struct function_unit_op *next; /* Next operation for this function unit. */ struct function_unit_op *next; /* Next operation for this function unit. */
int num; /* Ordinal for this operation type in unit. */ int num; /* Ordinal for this operation type in unit. */
int ready; /* Cost until data is ready. */ 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 /* Record information about each function unit mentioned in a
...@@ -207,14 +218,14 @@ struct function_unit ...@@ -207,14 +218,14 @@ struct function_unit
int simultaneity; /* Maximum number of simultaneous insns int simultaneity; /* Maximum number of simultaneous insns
on this function unit or 0 if unlimited. */ on this function unit or 0 if unlimited. */
rtx condexp; /* Expression TRUE for insn needing unit. */ 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. */ int num_opclasses; /* Number of different operation types. */
struct function_unit_op *ops; /* Pointer to first operation type. */ struct function_unit_op *ops; /* Pointer to first operation type. */
int needs_conflict_function; /* Nonzero if a conflict function required. */ 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 default_cost; /* Conflict cost, if constant. */
rtx max_busy_cost; /* Maximum conflict cost. */ struct range issue_delay; /* Range of issue delay values. */
int min_busy_delay; /* Minimum conflict cost. */ int max_blockage; /* Maximum time an insn blocks the unit. */
int max_busy_delay; /* Maximum conflict cost. */
}; };
/* Listheads of above structures. */ /* Listheads of above structures. */
...@@ -240,7 +251,7 @@ static int num_units; ...@@ -240,7 +251,7 @@ static int num_units;
/* Used as operand to `operate_exp': */ /* 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. */ /* Stores, for each insn code, the number of constraint alternatives. */
...@@ -301,6 +312,7 @@ static rtx copy_boolean (); ...@@ -301,6 +312,7 @@ static rtx copy_boolean ();
static void expand_delays (); static void expand_delays ();
static rtx operate_exp (); static rtx operate_exp ();
static void expand_units (); static void expand_units ();
static rtx simplify_knowing ();
static rtx encode_units_mask (); static rtx encode_units_mask ();
static void fill_attr (); static void fill_attr ();
static rtx substitute_address (); static rtx substitute_address ();
...@@ -349,6 +361,7 @@ static void write_upcase (); ...@@ -349,6 +361,7 @@ static void write_upcase ();
static void write_indent (); static void write_indent ();
static void write_eligible_delay (); static void write_eligible_delay ();
static void write_function_unit_info (); static void write_function_unit_info ();
static void write_complex_function ();
static int n_comma_elts (); static int n_comma_elts ();
static char *next_comma_elt (); static char *next_comma_elt ();
static struct attr_desc *find_attr (); static struct attr_desc *find_attr ();
...@@ -356,6 +369,7 @@ static void make_internal_attr (); ...@@ -356,6 +369,7 @@ static void make_internal_attr ();
static struct attr_value *find_most_used (); static struct attr_value *find_most_used ();
static rtx find_single_value (); static rtx find_single_value ();
static rtx make_numeric_value (); static rtx make_numeric_value ();
static void extend_range ();
char *xrealloc (); char *xrealloc ();
char *xmalloc (); char *xmalloc ();
static void fatal (); static void fatal ();
...@@ -1504,10 +1518,25 @@ operate_exp (op, left, right) ...@@ -1504,10 +1518,25 @@ operate_exp (op, left, right)
i = left_value - right_value; i = left_value - right_value;
break; 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 OR_OP:
i = left_value | right_value; i = left_value | right_value;
break; 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: case MAX_OP:
if (left_value > right_value) if (left_value > right_value)
i = left_value; i = left_value;
...@@ -1515,6 +1544,13 @@ operate_exp (op, left, right) ...@@ -1515,6 +1544,13 @@ operate_exp (op, left, right)
i = right_value; i = right_value;
break; break;
case MIN_OP:
if (left_value < right_value)
i = left_value;
else
i = right_value;
break;
default: default:
abort (); abort ();
} }
...@@ -1646,7 +1682,15 @@ operate_exp (op, left, right) ...@@ -1646,7 +1682,15 @@ operate_exp (op, left, right)
and a `<name>_unit_conflict_cost' function is given an insn already 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 executing on the unit and a candidate to execute and will give the
cost from the time the executing insn started until the candidate 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 static void
expand_units () expand_units ()
...@@ -1659,19 +1703,47 @@ expand_units () ...@@ -1659,19 +1703,47 @@ expand_units ()
char *str; char *str;
int i, j, u, num, nvalues; int i, j, u, num, nvalues;
/* Validate the expressions we were given for the conditions and busy cost. /* Rebuild the condition for the unit to share the RTL expressions.
Then make attributes for use in the conflict function. */ 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 (unit = units; unit; unit = unit->next)
for (op = unit->ops; op; op = op->next) {
{ rtx min_issue = make_numeric_value (unit->issue_delay.min);
op->condexp = check_attr_test (op->condexp, 0);
op->busyexp = check_attr_value (make_canonical (NULL_ATTR, unit->condexp = check_attr_test (unit->condexp, 0);
op->busyexp),
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); NULL_ATTR);
str = attr_printf (strlen (unit->name) + 11, "*%s_case_%d", issue_exp = simplify_knowing (issue_exp, unit->condexp);
unit->name, op->num); op->issue_exp = issue_exp;
make_internal_attr (str, op->busyexp, 1);
} /* 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 /* Compute the mask of function units used. Initially, the unitsmask is
zero. Set up a conditional to compute each unit's contribution. */ zero. Set up a conditional to compute each unit's contribution. */
...@@ -1682,7 +1754,7 @@ expand_units () ...@@ -1682,7 +1754,7 @@ expand_units ()
/* Merge each function unit into the unit mask attributes. */ /* Merge each function unit into the unit mask attributes. */
for (unit = units; unit; unit = unit->next) 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); XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
unitsmask = operate_exp (OR_OP, unitsmask, newexp); unitsmask = operate_exp (OR_OP, unitsmask, newexp);
} }
...@@ -1788,13 +1860,128 @@ expand_units () ...@@ -1788,13 +1860,128 @@ expand_units ()
XVECEXP (readycost, 0, nvalues * 2 + 1) = make_numeric_value (value); 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) 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 else
str = "*result_ready_cost"; 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); make_internal_attr (str, readycost, 0);
} }
...@@ -1804,7 +1991,8 @@ expand_units () ...@@ -1804,7 +1991,8 @@ expand_units ()
{ {
rtx caseexp; rtx caseexp;
if (unit->min_busy_delay == unit->max_busy_delay) if (! unit->needs_conflict_function
&& ! unit->needs_blockage_function)
continue; continue;
caseexp = rtx_alloc (COND); caseexp = rtx_alloc (COND);
...@@ -1833,6 +2021,21 @@ expand_units () ...@@ -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 /* 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 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 used; on output, the value is the unit number (zero based) if one
...@@ -3170,11 +3373,11 @@ simplify_by_exploding (exp) ...@@ -3170,11 +3373,11 @@ simplify_by_exploding (exp)
rtx list = 0, link, condexp, defval; rtx list = 0, link, condexp, defval;
struct dimension *space; struct dimension *space;
rtx *condtest, *condval; rtx *condtest, *condval;
int i, j, total, ndim; int i, j, total, ndim = 0;
int most_tests, num_marks, new_marks; int most_tests, num_marks, new_marks;
/* Locate all the EQ_ATTR expressions. */ /* 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); unmark_used_attributes (list, 0, 0);
return exp; return exp;
...@@ -3186,9 +3389,6 @@ simplify_by_exploding (exp) ...@@ -3186,9 +3389,6 @@ simplify_by_exploding (exp)
cover the domain of the attribute. This makes the expanded COND form cover the domain of the attribute. This makes the expanded COND form
order independent. */ order independent. */
ndim = 0;
for (link = list; link; link = XEXP (link, 1))
ndim++;
space = (struct dimension *) alloca (ndim * sizeof (struct dimension)); space = (struct dimension *) alloca (ndim * sizeof (struct dimension));
total = 1; total = 1;
...@@ -3289,6 +3489,10 @@ simplify_by_exploding (exp) ...@@ -3289,6 +3489,10 @@ simplify_by_exploding (exp)
if (num_marks == 0) if (num_marks == 0)
return exp; 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 /* 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 complex method where tests with the same value were combined didn't
seem to improve things.) */ seem to improve things.) */
...@@ -3311,8 +3515,9 @@ simplify_by_exploding (exp) ...@@ -3311,8 +3515,9 @@ simplify_by_exploding (exp)
tests have known value. */ tests have known value. */
static int static int
find_and_mark_used_attributes (exp, terms) find_and_mark_used_attributes (exp, terms, nterms)
rtx exp, *terms; rtx exp, *terms;
int *nterms;
{ {
int i; int i;
...@@ -3325,28 +3530,29 @@ find_and_mark_used_attributes (exp, terms) ...@@ -3325,28 +3530,29 @@ find_and_mark_used_attributes (exp, terms)
XEXP (link, 0) = exp; XEXP (link, 0) = exp;
XEXP (link, 1) = *terms; XEXP (link, 1) = *terms;
*terms = link; *terms = link;
*nterms += 1;
MEM_VOLATILE_P (exp) = 1; MEM_VOLATILE_P (exp) = 1;
} }
case CONST_STRING: case CONST_STRING:
return 1; return 1;
case IF_THEN_ELSE: 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; return 0;
case IOR: case IOR:
case AND: 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; return 0;
case NOT: 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 0;
return 1; return 1;
case COND: case COND:
for (i = 0; i < XVECLEN (exp, 0); i++) 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; 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 0;
return 1; return 1;
} }
...@@ -3935,15 +4141,21 @@ gen_unit (def) ...@@ -3935,15 +4141,21 @@ gen_unit (def)
{ {
struct function_unit *unit; struct function_unit *unit;
struct function_unit_op *op; 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 /* See if we have already seen this function unit. If so, check that
the multiplicity and simultaneity values are the same. If not, make the multiplicity and simultaneity values are the same. If not, make
a structure for this function unit. */ a structure for this function unit. */
for (unit = units; unit; unit = unit->next) 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) if (unit->multiplicity != multiplicity
|| unit->simultaneity != XINT (def, 2)) || unit->simultaneity != simultaneity)
fatal ("Differing specifications given for `%s' function unit.", fatal ("Differing specifications given for `%s' function unit.",
unit->name); unit->name);
break; break;
...@@ -3952,27 +4164,28 @@ gen_unit (def) ...@@ -3952,27 +4164,28 @@ gen_unit (def)
if (unit == 0) if (unit == 0)
{ {
unit = (struct function_unit *) xmalloc (sizeof (struct function_unit)); unit = (struct function_unit *) xmalloc (sizeof (struct function_unit));
unit->name = XSTR (def, 0); unit->name = name;
unit->multiplicity = XINT (def, 1); unit->multiplicity = multiplicity;
unit->simultaneity = XINT (def, 2); unit->simultaneity = simultaneity;
unit->issue_delay.min = unit->issue_delay.max = issue_delay;
unit->num = num_units++; unit->num = num_units++;
unit->num_opclasses = 0; unit->num_opclasses = 0;
unit->condexp = false_rtx; unit->condexp = false_rtx;
unit->ops = 0; unit->ops = 0;
unit->next = units; unit->next = units;
unit->min_busy_delay = unit->max_busy_delay = XINT (def, 5);
units = unit; units = unit;
} }
/* Make a new operation class structure entry and initialize it. */ /* Make a new operation class structure entry and initialize it. */
op = (struct function_unit_op *) xmalloc (sizeof (struct function_unit_op)); 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->num = unit->num_opclasses++;
op->ready = XINT (def, 4); op->ready = ready_cost;
op->issue_delay = issue_delay;
op->next = unit->ops; op->next = unit->ops;
unit->ops = op; 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. */ vector was specified. */
if (XVEC (def, 6)) if (XVEC (def, 6))
{ {
...@@ -3983,17 +4196,13 @@ gen_unit (def) ...@@ -3983,17 +4196,13 @@ gen_unit (def)
for (i = 0; i < XVECLEN (def, 6); i++) for (i = 0; i < XVECLEN (def, 6); i++)
orexp = insert_right_side (IOR, orexp, XVECEXP (def, 6, i), -2); orexp = insert_right_side (IOR, orexp, XVECEXP (def, 6, i), -2);
op->busyexp = attr_rtx (IF_THEN_ELSE, orexp, op->conflict_exp = orexp;
make_numeric_value (XINT (def, 5)), extend_range (&unit->issue_delay, 1, issue_delay);
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));
} }
else else
{ {
op->busyexp = make_numeric_value (XINT (def, 5)); op->conflict_exp = true_rtx;
unit->min_busy_delay = MIN (unit->min_busy_delay, XINT (def, 5)); extend_range (&unit->issue_delay, issue_delay, issue_delay);
unit->max_busy_delay = MAX (unit->max_busy_delay, XINT (def, 5));
} }
/* Merge our conditional into that of the function unit so we can determine /* Merge our conditional into that of the function unit so we can determine
...@@ -4249,6 +4458,14 @@ max_attr_value (exp) ...@@ -4249,6 +4458,14 @@ max_attr_value (exp)
current_max = n; 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 else
abort (); abort ();
...@@ -4331,10 +4548,12 @@ write_attr_get (attr) ...@@ -4331,10 +4548,12 @@ write_attr_get (attr)
/* Write out start of function, then all values with explicit `case' lines, /* Write out start of function, then all values with explicit `case' lines,
then a `default', then the value with the most uses. */ then a `default', then the value with the most uses. */
if (attr->is_numeric) if (!attr->is_numeric)
printf ("int\n");
else
printf ("enum attr_%s\n", attr->name); 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 /* If the attribute name starts with a star, the remainder is the name of
the subroutine to use, instead of `get_attr_...'. */ the subroutine to use, instead of `get_attr_...'. */
...@@ -4583,7 +4802,12 @@ write_attr_valueq (attr, s) ...@@ -4583,7 +4802,12 @@ write_attr_valueq (attr, s)
char *s; char *s;
{ {
if (attr->is_numeric) 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 else
{ {
write_upcase (attr->name); write_upcase (attr->name);
...@@ -4758,107 +4982,27 @@ static void ...@@ -4758,107 +4982,27 @@ static void
write_function_unit_info () write_function_unit_info ()
{ {
struct function_unit *unit; 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; int i;
/* Write out conflict routines for function units. Don't bother writing /* 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) for (unit = units; unit; unit = unit->next)
{ {
/* Record the maximum busy cost. */ if (unit->needs_blockage_function)
unit->max_busy_cost = make_numeric_value (unit->max_busy_delay); write_complex_function (unit, "blockage", "block");
/* If the minimum and maximum conflict costs are the same, there /* If the minimum and maximum conflict costs are the same, there
is only one value, so we don't need a function. */ 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 = make_numeric_value (unit->issue_delay.max);
unit->default_cost = unit->max_busy_cost;
continue; continue;
} }
/* The function first computes the case from the candidate insn. */ /* The function first computes the case from the candidate insn. */
unit->needs_conflict_function = 1;
unit->default_cost = make_numeric_value (0); unit->default_cost = make_numeric_value (0);
write_complex_function (unit, "conflict_cost", "cost");
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");
} }
/* Now that all functions have been written, write the table describing /* Now that all functions have been written, write the table describing
...@@ -4875,13 +5019,25 @@ write_function_unit_info () ...@@ -4875,13 +5019,25 @@ write_function_unit_info ()
if (unit->num == i) if (unit->num == i)
break; 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->name, 1 << unit->num, unit->multiplicity,
unit->simultaneity, XSTR (unit->default_cost, 0), 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) 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 else
printf ("0"); printf ("0");
...@@ -4890,6 +5046,93 @@ write_function_unit_info () ...@@ -4890,6 +5046,93 @@ write_function_unit_info ()
printf ("};\n\n"); 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. */ /* This page contains miscellaneous utility routines. */
...@@ -4996,6 +5239,7 @@ make_internal_attr (name, value, special) ...@@ -4996,6 +5239,7 @@ make_internal_attr (name, value, special)
attr->is_const = 0; attr->is_const = 0;
attr->is_special = (special & 1) != 0; attr->is_special = (special & 1) != 0;
attr->negative_ok = (special & 2) != 0; attr->negative_ok = (special & 2) != 0;
attr->unsigned_p = (special & 4) != 0;
attr->default_val = get_attr_value (value, attr, -2); attr->default_val = get_attr_value (value, attr, -2);
} }
...@@ -5067,6 +5311,16 @@ make_numeric_value (n) ...@@ -5067,6 +5311,16 @@ make_numeric_value (n)
return exp; 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 * char *
xrealloc (ptr, size) xrealloc (ptr, size)
char *ptr; char *ptr;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment