📄 genattrtab.c
字号:
exp = newexp; /* Fall through to COND case since this is now a COND. */ case COND: cond: { int allsame = 1; rtx defval; /* First, check for degenerate COND. */ if (XVECLEN (exp, 0) == 0) return make_canonical (attr, XEXP (exp, 1)); defval = XEXP (exp, 1) = make_canonical (attr, XEXP (exp, 1)); for (i = 0; i < XVECLEN (exp, 0); i += 2) { XVECEXP (exp, 0, i) = copy_boolean (XVECEXP (exp, 0, i)); XVECEXP (exp, 0, i + 1) = make_canonical (attr, XVECEXP (exp, 0, i + 1)); if (! rtx_equal_p (XVECEXP (exp, 0, i + 1), defval)) allsame = 0; } if (allsame) return defval; break; } } return exp;}static rtxcopy_boolean (exp) rtx exp;{ if (GET_CODE (exp) == AND || GET_CODE (exp) == IOR) return attr_rtx (GET_CODE (exp), copy_boolean (XEXP (exp, 0)), copy_boolean (XEXP (exp, 1))); return exp;}/* Given a value and an attribute description, return a `struct attr_value *' that represents that value. This is either an existing structure, if the value has been previously encountered, or a newly-created structure. `insn_code' is the code of an insn whose attribute has the specified value (-2 if not processing an insn). We ensure that all insns for a given value have the same number of alternatives if the value checks alternatives. */static struct attr_value *get_attr_value (value, attr, insn_code) rtx value; struct attr_desc *attr; int insn_code;{ struct attr_value *av; int num_alt = 0; value = make_canonical (attr, value); if (compares_alternatives_p (value)) { if (insn_code < 0 || insn_alternatives == NULL) fatal ("(eq_attr \"alternatives\" ...) used in non-insn context"); else num_alt = insn_alternatives[insn_code]; } for (av = attr->first_value; av; av = av->next) if (rtx_equal_p (value, av->value) && (num_alt == 0 || av->first_insn == NULL || insn_alternatives[av->first_insn->insn_code])) return av; av = (struct attr_value *) oballoc (sizeof (struct attr_value)); av->value = value; av->next = attr->first_value; attr->first_value = av; av->first_insn = NULL; av->num_insns = 0; av->has_asm_insn = 0; return av;}/* After all DEFINE_DELAYs have been read in, create internal attributes to generate the required routines. First, we compute the number of delay slots for each insn (as a COND of each of the test expressions in DEFINE_DELAYs). Then, if more than one delay type is specified, we compute a similar function giving the DEFINE_DELAY ordinal for each insn. Finally, for each [DEFINE_DELAY, slot #] pair, we compute an attribute that tells whether a given insn can be in that delay slot. Normal attribute filling and optimization expands these to contain the information needed to handle delay slots. */static voidexpand_delays (){ struct delay_desc *delay; rtx condexp; rtx newexp; int i; char *p; /* First, generate data for `num_delay_slots' function. */ condexp = rtx_alloc (COND); XVEC (condexp, 0) = rtvec_alloc (num_delays * 2); XEXP (condexp, 1) = make_numeric_value (0); for (i = 0, delay = delays; delay; i += 2, delay = delay->next) { XVECEXP (condexp, 0, i) = XEXP (delay->def, 0); XVECEXP (condexp, 0, i + 1) = make_numeric_value (XVECLEN (delay->def, 1) / 3); } make_internal_attr ("*num_delay_slots", condexp, 0); /* If more than one delay type, do the same for computing the delay type. */ if (num_delays > 1) { condexp = rtx_alloc (COND); XVEC (condexp, 0) = rtvec_alloc (num_delays * 2); XEXP (condexp, 1) = make_numeric_value (0); for (i = 0, delay = delays; delay; i += 2, delay = delay->next) { XVECEXP (condexp, 0, i) = XEXP (delay->def, 0); XVECEXP (condexp, 0, i + 1) = make_numeric_value (delay->num); } make_internal_attr ("*delay_type", condexp, 1); } /* For each delay possibility and delay slot, compute an eligibility attribute for non-annulled insns and for each type of annulled (annul if true and annul if false). */ for (delay = delays; delay; delay = delay->next) { for (i = 0; i < XVECLEN (delay->def, 1); i += 3) { condexp = XVECEXP (delay->def, 1, i); if (condexp == 0) condexp = false_rtx; newexp = attr_rtx (IF_THEN_ELSE, condexp, make_numeric_value (1), make_numeric_value (0)); p = attr_printf (sizeof ("*delay__") + MAX_DIGITS*2, "*delay_%d_%d", delay->num, i / 3); make_internal_attr (p, newexp, 1); if (have_annul_true) { condexp = XVECEXP (delay->def, 1, i + 1); if (condexp == 0) condexp = false_rtx; newexp = attr_rtx (IF_THEN_ELSE, condexp, make_numeric_value (1), make_numeric_value (0)); p = attr_printf (sizeof ("*annul_true__") + MAX_DIGITS*2, "*annul_true_%d_%d", delay->num, i / 3); make_internal_attr (p, newexp, 1); } if (have_annul_false) { condexp = XVECEXP (delay->def, 1, i + 2); if (condexp == 0) condexp = false_rtx; newexp = attr_rtx (IF_THEN_ELSE, condexp, make_numeric_value (1), make_numeric_value (0)); p = attr_printf (sizeof ("*annul_false__") + MAX_DIGITS*2, "*annul_false_%d_%d", delay->num, i / 3); make_internal_attr (p, newexp, 1); } } }}/* This function is given a left and right side expression and an operator. Each side is a conditional expression, each alternative of which has a numerical value. The function returns another conditional expression which, for every possible set of condition values, returns a value that is the operator applied to the values of the two sides. Since this is called early, it must also support IF_THEN_ELSE. */static rtxoperate_exp (op, left, right) enum operator op; rtx left, right;{ int left_value, right_value; rtx newexp; int i; /* If left is a string, apply operator to it and the right side. */ if (GET_CODE (left) == CONST_STRING) { /* If right is also a string, just perform the operation. */ if (GET_CODE (right) == CONST_STRING) { left_value = atoi (XSTR (left, 0)); right_value = atoi (XSTR (right, 0)); switch (op) { case PLUS_OP: i = left_value + right_value; break; case MINUS_OP: 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; else i = right_value; break; case MIN_OP: if (left_value < right_value) i = left_value; else i = right_value; break; default: abort (); } return make_numeric_value (i); } else if (GET_CODE (right) == IF_THEN_ELSE) { /* Apply recursively to all values within. */ rtx newleft = operate_exp (op, left, XEXP (right, 1)); rtx newright = operate_exp (op, left, XEXP (right, 2)); if (rtx_equal_p (newleft, newright)) return newleft; return attr_rtx (IF_THEN_ELSE, XEXP (right, 0), newleft, newright); } else if (GET_CODE (right) == COND) { int allsame = 1; rtx defval; newexp = rtx_alloc (COND); XVEC (newexp, 0) = rtvec_alloc (XVECLEN (right, 0)); defval = XEXP (newexp, 1) = operate_exp (op, left, XEXP (right, 1)); for (i = 0; i < XVECLEN (right, 0); i += 2) { XVECEXP (newexp, 0, i) = XVECEXP (right, 0, i); XVECEXP (newexp, 0, i + 1) = operate_exp (op, left, XVECEXP (right, 0, i + 1)); if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1), defval)) allsame = 0; } /* If the resulting cond is trivial (all alternatives give the same value), optimize it away. */ if (allsame) { obstack_free (rtl_obstack, newexp); return operate_exp (op, left, XEXP (right, 1)); } /* If the result is the same as the RIGHT operand, just use that. */ if (rtx_equal_p (newexp, right)) { obstack_free (rtl_obstack, newexp); return right; } return newexp; } else fatal ("Badly formed attribute value"); } /* Otherwise, do recursion the other way. */ else if (GET_CODE (left) == IF_THEN_ELSE) { rtx newleft = operate_exp (op, XEXP (left, 1), right); rtx newright = operate_exp (op, XEXP (left, 2), right); if (rtx_equal_p (newleft, newright)) return newleft; return attr_rtx (IF_THEN_ELSE, XEXP (left, 0), newleft, newright); } else if (GET_CODE (left) == COND) { int allsame = 1; rtx defval; newexp = rtx_alloc (COND); XVEC (newexp, 0) = rtvec_alloc (XVECLEN (left, 0)); defval = XEXP (newexp, 1) = operate_exp (op, XEXP (left, 1), right); for (i = 0; i < XVECLEN (left, 0); i += 2) { XVECEXP (newexp, 0, i) = XVECEXP (left, 0, i); XVECEXP (newexp, 0, i + 1) = operate_exp (op, XVECEXP (left, 0, i + 1), right); if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1), defval)) allsame = 0; } /* If the cond is trivial (all alternatives give the same value), optimize it away. */ if (allsame) { obstack_free (rtl_obstack, newexp); return operate_exp (op, XEXP (left, 1), right); } /* If the result is the same as the LEFT operand, just use that. */ if (rtx_equal_p (newexp, left)) { obstack_free (rtl_obstack, newexp); return left; } return newexp; } else fatal ("Badly formed attribute value."); /* NOTREACHED */ return NULL;}/* Once all attributes and DEFINE_FUNCTION_UNITs have been read, we construct a number of attributes. The first produces a function `function_units_used' which is given an insn and produces an encoding showing which function units are required for the execution of that insn. If the value is non-negative, the insn uses that unit; otherwise, the value is a one's compliment mask of units used. The second produces a function `result_ready_cost' which is used to determine the time that the result of an insn will be ready and hence a worst-case schedule. Both of these produce quite complex expressions which are then set as the default value of internal attributes. Normal attribute simplification should produce reasonable expressions. For each unit, a `<name>_unit_ready_cost' function will take an insn and give the delay until that unit will be ready with the result 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). 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 voidexpand_units (){ struct function_unit *unit, **unit_num; struct function_unit_op *op, **op_array, ***unit_ops; rtx unitsmask; rtx readycost; rtx newexp; char *str; int i, j, u, num, nvalues; /* 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) { 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); 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) + sizeof ("*_cost_") + MAX_DIGITS, "*%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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -