⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 genattrtab.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
	}    }  /* 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 + -