- for (unit = units; unit; unit = unit->next)
- {
- unit_num[num_units]->num_opclasses += unit->num_opclasses;
- unit_num[unit->num] = unit;
- unit_ops[unit->num] = op_array =
- xmalloc (unit->num_opclasses * sizeof (struct function_unit_op *));
-
- for (op = unit->ops; op; op = op->next)
- op_array[op->num] = op;
- }
-
- /* Compose the array of ops for the extra unit. */
- unit_ops[num_units] = op_array =
- xmalloc (unit_num[num_units]->num_opclasses
- * sizeof (struct function_unit_op *));
-
- for (unit = units, i = 0; unit; i += unit->num_opclasses, unit = unit->next)
- memcpy (&op_array[i], unit_ops[unit->num],
- unit->num_opclasses * sizeof (struct function_unit_op *));
-
- /* Compute the ready cost function for each unit by computing the
- condition for each non-default value. */
- for (u = 0; u <= num_units; u++)
- {
- rtx orexp;
- int value;
-
- unit = unit_num[u];
- op_array = unit_ops[unit->num];
- num = unit->num_opclasses;
-
- /* Sort the array of ops into increasing ready cost order. */
- for (i = 0; i < num; i++)
- for (j = num - 1; j > i; j--)
- if (op_array[j - 1]->ready < op_array[j]->ready)
- {
- op = op_array[j];
- op_array[j] = op_array[j - 1];
- op_array[j - 1] = op;
- }
-
- /* Determine how many distinct non-default ready cost values there
- are. We use a default ready cost value of 1. */
- nvalues = 0; value = 1;
- for (i = num - 1; i >= 0; i--)
- if (op_array[i]->ready > value)
- {
- value = op_array[i]->ready;
- nvalues++;
- }
-
- if (nvalues == 0)
- readycost = make_numeric_value (1);
- else
- {
- /* Construct the ready cost expression as a COND of each value from
- the largest to the smallest. */
- readycost = rtx_alloc (COND);
- XVEC (readycost, 0) = rtvec_alloc (nvalues * 2);
- XEXP (readycost, 1) = make_numeric_value (1);
-
- nvalues = 0;
- orexp = false_rtx;
- value = op_array[0]->ready;
- for (i = 0; i < num; i++)
- {
- op = op_array[i];
- if (op->ready <= 1)
- break;
- else if (op->ready == value)
- orexp = insert_right_side (IOR, orexp, op->condexp, -2, -2);
- else
- {
- XVECEXP (readycost, 0, nvalues * 2) = orexp;
- XVECEXP (readycost, 0, nvalues * 2 + 1)
- = make_numeric_value (value);
- nvalues++;
- value = op->ready;
- orexp = op->condexp;
- }
- }
- XVECEXP (readycost, 0, nvalues * 2) = orexp;
- XVECEXP (readycost, 0, nvalues * 2 + 1) = make_numeric_value (value);
- }
-
- if (u < num_units)
- {
- 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.
-
- We compute the blockage cost for each E for every possible C.
- Thus OP represents E, and READYCOST is a list of values for
- every possible C.
-
- The issue delay function for C is op->issue_exp and is used to
- write the `<name>_unit_conflict_cost' function. Symbolically
- 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 nonzero 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 = 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) + sizeof "*_block_"
- + MAX_DIGITS),
- "*%s_block_%d", unit->name, op->num);
- make_internal_attr (str, blockage, ATTR_SPECIAL);
- }
-
- /* Record MAX (BLOCKAGE (*,*)). */
- {
- int unknown;
- unit->max_blockage = max_attr_value (max_blockage, &unknown);
- }
-
- /* 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 its value. */
- newexp = operate_exp (RANGE_OP, min_blockage, max_blockage);
- newexp = simplify_knowing (newexp, unit->condexp);
-
- str = attr_printf ((strlen (unit->name)
- + sizeof "*_unit_blockage_range"),
- "*%s_unit_blockage_range", unit->name);
- make_internal_attr (str, newexp, (ATTR_STATIC|ATTR_BLOCKAGE|ATTR_UNSIGNED));
- }
-
- str = attr_printf (strlen (unit->name) + sizeof "*_unit_ready_cost",
- "*%s_unit_ready_cost", unit->name);
- make_internal_attr (str, readycost, ATTR_STATIC);
- }
- else
- {
- /* Make an attribute for the ready_cost function. Simplifying
- further with simplify_by_exploding doesn't win. */
- str = "*result_ready_cost";
- make_internal_attr (str, readycost, ATTR_NONE);
- }
- }
-
- /* For each unit that requires a conflict cost function, make an attribute
- that maps insns to the operation number. */
- for (unit = units; unit; unit = unit->next)
- {
- rtx caseexp;
-
- if (! unit->needs_conflict_function
- && ! unit->needs_blockage_function)
- continue;
-
- caseexp = rtx_alloc (COND);
- XVEC (caseexp, 0) = rtvec_alloc ((unit->num_opclasses - 1) * 2);
-
- for (op = unit->ops; op; op = op->next)
- {
- /* Make our adjustment to the COND being computed. If we are the
- last operation class, place our values into the default of the
- COND. */
- if (op->num == unit->num_opclasses - 1)
- {
- XEXP (caseexp, 1) = make_numeric_value (op->num);
- }
- else
- {
- XVECEXP (caseexp, 0, op->num * 2) = op->condexp;
- XVECEXP (caseexp, 0, op->num * 2 + 1)
- = make_numeric_value (op->num);
- }
- }
-
- /* Simplifying caseexp with simplify_by_exploding doesn't win. */
- str = attr_printf (strlen (unit->name) + sizeof "*_cases",
- "*%s_cases", unit->name);
- make_internal_attr (str, caseexp, ATTR_SPECIAL);
- }
-}
-
-/* Simplify EXP given KNOWN_TRUE. */
-
-static rtx
-simplify_knowing (rtx exp, rtx known_true)
-{
- if (GET_CODE (exp) != CONST_STRING)
- {
- int unknown = 0, max;
- max = max_attr_value (exp, &unknown);
- if (! unknown)
- {
- exp = attr_rtx (IF_THEN_ELSE, known_true, exp,
- make_numeric_value (max));
- 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
- and only one unit is used or the one's complement of the bitmask. */
-
-static rtx
-encode_units_mask (rtx x)
-{
- int i;
- int j;
- enum rtx_code code;
- const char *fmt;
-
- code = GET_CODE (x);
-
- switch (code)
- {
- case CONST_STRING:
- i = atoi (XSTR (x, 0));
- if (i < 0)
- /* The sign bit encodes a one's complement mask. */
- abort ();
- else if (i != 0 && i == (i & -i))
- /* Only one bit is set, so yield that unit number. */
- for (j = 0; (i >>= 1) != 0; j++)
- ;
- else
- j = ~i;
- return attr_rtx (CONST_STRING, attr_printf (MAX_DIGITS, "%d", j));
-
- case REG:
- case QUEUED:
- case CONST_INT:
- case CONST_DOUBLE:
- case CONST_VECTOR:
- case SYMBOL_REF:
- case CODE_LABEL:
- case PC:
- case CC0:
- case EQ_ATTR:
- case EQ_ATTR_ALT:
- return x;
-
- default:
- break;
- }
-
- /* Compare the elements. If any pair of corresponding elements
- fail to match, return 0 for the whole things. */
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- switch (fmt[i])
- {
- case 'V':
- case 'E':
- for (j = 0; j < XVECLEN (x, i); j++)
- XVECEXP (x, i, j) = encode_units_mask (XVECEXP (x, i, j));
- break;
-
- case 'e':
- XEXP (x, i) = encode_units_mask (XEXP (x, i));
- break;
- }
- }
- return x;
-}
-
-/* Once all attributes and insns have been read and checked, we construct for
- each attribute value a list of all the insns that have that value for
- the attribute. */
-
-static void
-fill_attr (struct attr_desc *attr)
-{
- struct attr_value *av;
- struct insn_ent *ie;
- struct insn_def *id;
- int i;
- rtx value;
-
- /* Don't fill constant attributes. The value is independent of
- any particular insn. */
- if (attr->is_const)
- return;
-
- for (id = defs; id; id = id->next)
- {
- /* If no value is specified for this insn for this attribute, use the
- default. */
- value = NULL;
- if (XVEC (id->def, id->vec_idx))
- for (i = 0; i < XVECLEN (id->def, id->vec_idx); i++)
- if (! strcmp_check (XSTR (XEXP (XVECEXP (id->def, id->vec_idx, i), 0), 0),
- attr->name))
- value = XEXP (XVECEXP (id->def, id->vec_idx, i), 1);
-
- if (value == NULL)
- av = attr->default_val;
- else
- av = get_attr_value (value, attr, id->insn_code);
-
- ie = oballoc (sizeof (struct insn_ent));
- ie->insn_code = id->insn_code;
- ie->insn_index = id->insn_code;
- insert_insn_ent (av, ie);
- }
-}
-
-/* Given an expression EXP, see if it is a COND or IF_THEN_ELSE that has a
- test that checks relative positions of insns (uses MATCH_DUP or PC).
- If so, replace it with what is obtained by passing the expression to
- ADDRESS_FN. If not but it is a COND or IF_THEN_ELSE, call this routine
- recursively on each value (including the default value). Otherwise,
- return the value returned by NO_ADDRESS_FN applied to EXP. */
-
-static rtx
-substitute_address (rtx exp, rtx (*no_address_fn) (rtx),
- rtx (*address_fn) (rtx))
-{
- int i;
- rtx newexp;
-
- if (GET_CODE (exp) == COND)
- {
- /* See if any tests use addresses. */
- address_used = 0;
- for (i = 0; i < XVECLEN (exp, 0); i += 2)
- walk_attr_value (XVECEXP (exp, 0, i));
-
- if (address_used)
- return (*address_fn) (exp);
-
- /* Make a new copy of this COND, replacing each element. */
- newexp = rtx_alloc (COND);
- XVEC (newexp, 0) = rtvec_alloc (XVECLEN (exp, 0));
- for (i = 0; i < XVECLEN (exp, 0); i += 2)
- {
- XVECEXP (newexp, 0, i) = XVECEXP (exp, 0, i);
- XVECEXP (newexp, 0, i + 1)
- = substitute_address (XVECEXP (exp, 0, i + 1),
- no_address_fn, address_fn);
- }
-
- XEXP (newexp, 1) = substitute_address (XEXP (exp, 1),
- no_address_fn, address_fn);
-
- return newexp;
- }
-
- else if (GET_CODE (exp) == IF_THEN_ELSE)
- {
- address_used = 0;
- walk_attr_value (XEXP (exp, 0));
- if (address_used)
- return (*address_fn) (exp);
-
- return attr_rtx (IF_THEN_ELSE,
- substitute_address (XEXP (exp, 0),
- no_address_fn, address_fn),
- substitute_address (XEXP (exp, 1),
- no_address_fn, address_fn),
- substitute_address (XEXP (exp, 2),
- no_address_fn, address_fn));
- }
-
- return (*no_address_fn) (exp);
-}
-
-/* Make new attributes from the `length' attribute. The following are made,
- each corresponding to a function called from `shorten_branches' or
- `get_attr_length':
-
- *insn_default_length This is the length of the insn to be returned
- by `get_attr_length' before `shorten_branches'
- has been called. In each case where the length
- depends on relative addresses, the largest
- possible is used. This routine is also used
- to compute the initial size of the insn.
-
- *insn_variable_length_p This returns 1 if the insn's length depends
- on relative addresses, zero otherwise.
-
- *insn_current_length This is only called when it is known that the
- insn has a variable length and returns the
- current length, based on relative addresses.
- */
-
-static void
-make_length_attrs (void)
-{
- static const char *new_names[] =
- {
- "*insn_default_length",
- "*insn_variable_length_p",
- "*insn_current_length"
- };
- static rtx (*const no_address_fn[]) (rtx) = {identity_fn, zero_fn, zero_fn};
- static rtx (*const address_fn[]) (rtx) = {max_fn, one_fn, identity_fn};
- size_t i;
- struct attr_desc *length_attr, *new_attr;
- struct attr_value *av, *new_av;
- struct insn_ent *ie, *new_ie;
-
- /* See if length attribute is defined. If so, it must be numeric. Make
- it special so we don't output anything for it. */
- length_attr = find_attr (&length_str, 0);
- if (length_attr == 0)
- return;
-
- if (! length_attr->is_numeric)
- fatal ("length attribute must be numeric");
-
- length_attr->is_const = 0;
- length_attr->is_special = 1;
-
- /* Make each new attribute, in turn. */
- for (i = 0; i < ARRAY_SIZE (new_names); i++)
- {
- make_internal_attr (new_names[i],
- substitute_address (length_attr->default_val->value,
- no_address_fn[i], address_fn[i]),
- ATTR_NONE);
- new_attr = find_attr (&new_names[i], 0);
- for (av = length_attr->first_value; av; av = av->next)
- for (ie = av->first_insn; ie; ie = ie->next)
- {
- new_av = get_attr_value (substitute_address (av->value,
- no_address_fn[i],
- address_fn[i]),
- new_attr, ie->insn_code);
- new_ie = oballoc (sizeof (struct insn_ent));
- new_ie->insn_code = ie->insn_code;
- new_ie->insn_index = ie->insn_index;
- insert_insn_ent (new_av, new_ie);
- }
- }
-}
-
-/* Utility functions called from above routine. */
-
-static rtx
-identity_fn (rtx exp)
-{
- return exp;
-}
-
-static rtx
-zero_fn (rtx exp ATTRIBUTE_UNUSED)
-{
- return make_numeric_value (0);
-}
-
-static rtx
-one_fn (rtx exp ATTRIBUTE_UNUSED)
-{
- return make_numeric_value (1);
-}
-
-static rtx
-max_fn (rtx exp)
-{
- int unknown;
- return make_numeric_value (max_attr_value (exp, &unknown));
-}