📄 genattrtab.c
字号:
} } /* Compute the mask of function units used. Initially, the unitsmask is zero. Set up a conditional to compute each unit's contribution. */ unitsmask = make_numeric_value (0); newexp = rtx_alloc (IF_THEN_ELSE); XEXP (newexp, 2) = make_numeric_value (0); /* Merge each function unit into the unit mask attributes. */ for (unit = units; unit; unit = unit->next) { XEXP (newexp, 0) = unit->condexp; XEXP (newexp, 1) = make_numeric_value (1 << unit->num); unitsmask = operate_exp (OR_OP, unitsmask, newexp); } /* Simplify the unit mask expression, encode it, and make an attribute for the function_units_used function. */ unitsmask = simplify_by_exploding (unitsmask); unitsmask = encode_units_mask (unitsmask); make_internal_attr ("*function_units_used", unitsmask, 2); /* Create an array of ops for each unit. Add an extra unit for the result_ready_cost function that has the ops of all other units. */ unit_ops = (struct function_unit_op ***) alloca ((num_units + 1) * sizeof (struct function_unit_op **)); unit_num = (struct function_unit **) alloca ((num_units + 1) * sizeof (struct function_unit *)); unit_num[num_units] = unit = (struct function_unit *) alloca (sizeof (struct function_unit)); unit->num = num_units; unit->num_opclasses = 0; 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 = (struct function_unit_op **) alloca (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 = (struct function_unit_op **) alloca (unit_num[num_units]->num_opclasses * sizeof (struct function_unit_op *)); for (unit = units, i = 0; unit; i += unit->num_opclasses, unit = unit->next) bcopy (unit_ops[unit->num], &op_array[i], 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); 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. 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) + sizeof ("*_block_") + MAX_DIGITS, "*%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) + sizeof ("*_unit_blockage_range"), "*%s_unit_blockage_range", unit->name); make_internal_attr (str, newexp, 4); } str = attr_printf (strlen (unit->name) + sizeof ("*_unit_ready_cost"), "*%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); } /* 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, 1); }}/* Simplify EXP given KNOWN_TRUE. */static rtxsimplify_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 and only one unit is used or the one's compliment of the bitmask. */static rtxencode_units_mask (x) rtx x;{ register int i; register int j; register enum rtx_code code; register char *fmt; code = GET_CODE (x); switch (code) { case CONST_STRING: i = atoi (XSTR (x, 0)); if (i < 0) abort (); /* The sign bit encodes a one's compliment mask. */ 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 SYMBOL_REF: case CODE_LABEL: case PC: case CC0: case EQ_ATTR: return x; } /* 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 voidfill_attr (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 (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 = (struct insn_ent *) 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 rtxsubstitute_address (exp, no_address_fn, address_fn) rtx exp; rtx (*no_address_fn) (); rtx (*address_fn) ();{ 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -