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

📄 genattrtab.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 5 页
字号:
	  /* 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)    {      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);	}    }  /* 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 ((char *) unit_ops[unit->num], (char *) &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, -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.  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 = operate_exp (POS_MINUS_OP, readycost,					  make_numeric_value (1));	      if (unit->simultaneity != 0)		{		  rtx filltime = make_numeric_value ((unit->simultaneity - 1)						     * unit->issue_delay.min);		  blockage = operate_exp (MIN_OP, blockage, filltime);		}	      blockage = operate_exp (POS_MINUS_OP,				      make_numeric_value (op->ready),				      blockage);	      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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -