(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:
parent
de19227a25
commit
bee757e1c0
546
gcc/genattrtab.c
546
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;
|
||||
|
Loading…
Reference in New Issue
Block a user