sched.c

来自「GCC编译器源代码」· C语言 代码 · 共 2,054 行 · 第 1/5 页

C
2,054
字号
  if (tick - clock > cost)    {      /* The scheduler is operating in reverse, so INSN is the executing	 insn and the unit's last insn is the candidate insn.  We want a	 more exact measure of the blockage if we execute INSN at CLOCK	 given when we committed the execution of the unit's last insn.	 The blockage value is given by either the unit's max blockage	 constant, blockage range function, or blockage function.  Use	 the most exact form for the given unit.  */      if (function_units[unit].blockage_range_function)	{	  if (function_units[unit].blockage_function)	    tick += (function_units[unit].blockage_function		     (insn, unit_last_insn[instance])		     - function_units[unit].max_blockage);	  else	    tick += ((int) MAX_BLOCKAGE_COST (blockage_range (unit, insn))		     - function_units[unit].max_blockage);	}      if (tick - clock > cost)	cost = tick - clock;    }  return cost;}/* Record INSN as having begun execution on the units encoded by UNIT at   time CLOCK.  */__inline static voidschedule_unit (unit, insn, clock)     int unit, clock;     rtx insn;{  int i;  if (unit >= 0)    {      int instance = unit;#if MAX_MULTIPLICITY > 1      /* Find the first free instance of the function unit and use that	 one.  We assume that one is free.  */      for (i = function_units[unit].multiplicity - 1; i > 0; i--)	{	  if (! actual_hazard_this_instance (unit, instance, insn, clock, 0))	    break;	  instance += FUNCTION_UNITS_SIZE;	}#endif      unit_last_insn[instance] = insn;      unit_tick[instance] = (clock + function_units[unit].max_blockage);    }  else    for (i = 0, unit = ~unit; unit; i++, unit >>= 1)      if ((unit & 1) != 0)	schedule_unit (i, insn, clock);}/* Return the actual hazard cost of executing INSN on the units encoded by   UNIT at time CLOCK if the previous actual hazard cost was COST.  */__inline static intactual_hazard (unit, insn, clock, cost)     int unit, clock, cost;     rtx insn;{  int i;  if (unit >= 0)    {      /* Find the instance of the function unit with the minimum hazard.  */      int instance = unit;      int best_cost = actual_hazard_this_instance (unit, instance, insn,						   clock, cost);      int this_cost;#if MAX_MULTIPLICITY > 1      if (best_cost > cost)	{	  for (i = function_units[unit].multiplicity - 1; i > 0; i--)	    {	      instance += FUNCTION_UNITS_SIZE;	      this_cost = actual_hazard_this_instance (unit, instance, insn,						       clock, cost);	      if (this_cost < best_cost)		{		  best_cost = this_cost;		  if (this_cost <= cost)		    break;		}	    }	}#endif      cost = MAX (cost, best_cost);    }  else    for (i = 0, unit = ~unit; unit; i++, unit >>= 1)      if ((unit & 1) != 0)	cost = actual_hazard (i, insn, clock, cost);  return cost;}/* Return the potential hazard cost of executing an instruction on the   units encoded by UNIT if the previous potential hazard cost was COST.   An insn with a large blockage time is chosen in preference to one   with a smaller time; an insn that uses a unit that is more likely   to be used is chosen in preference to one with a unit that is less   used.  We are trying to minimize a subsequent actual hazard.  */__inline static intpotential_hazard (unit, insn, cost)     int unit, cost;     rtx insn;{  int i, ncost;  unsigned int minb, maxb;  if (unit >= 0)    {      minb = maxb = function_units[unit].max_blockage;      if (maxb > 1)	{	  if (function_units[unit].blockage_range_function)	    {	      maxb = minb = blockage_range (unit, insn);	      maxb = MAX_BLOCKAGE_COST (maxb);	      minb = MIN_BLOCKAGE_COST (minb);	    }	  if (maxb > 1)	    {	      /* Make the number of instructions left dominate.  Make the		 minimum delay dominate the maximum delay.  If all these		 are the same, use the unit number to add an arbitrary		 ordering.  Other terms can be added.  */	      ncost = minb * 0x40 + maxb;	      ncost *= (unit_n_insns[unit] - 1) * 0x1000 + unit;	      if (ncost > cost)		cost = ncost;	    }	}    }  else    for (i = 0, unit = ~unit; unit; i++, unit >>= 1)      if ((unit & 1) != 0)	cost = potential_hazard (i, insn, cost);  return cost;}/* Compute cost of executing INSN given the dependence LINK on the insn USED.   This is the number of virtual cycles taken between instruction issue and   instruction results.  */__inline static intinsn_cost (insn, link, used)     rtx insn, link, used;{  register int cost = INSN_COST (insn);  if (cost == 0)    {      recog_memoized (insn);      /* A USE insn, or something else we don't need to understand.	 We can't pass these directly to result_ready_cost because it will	 trigger a fatal error for unrecognizable insns.  */      if (INSN_CODE (insn) < 0)	{	  INSN_COST (insn) = 1;	  return 1;	}      else	{	  cost = result_ready_cost (insn);	  if (cost < 1)	    cost = 1;	  INSN_COST (insn) = cost;	}    }  /* A USE insn should never require the value used to be computed.  This     allows the computation of a function's result and parameter values to     overlap the return and call.  */  recog_memoized (used);  if (INSN_CODE (used) < 0)    LINK_COST_FREE (link) = 1;  /* If some dependencies vary the cost, compute the adjustment.  Most     commonly, the adjustment is complete: either the cost is ignored     (in the case of an output- or anti-dependence), or the cost is     unchanged.  These values are cached in the link as LINK_COST_FREE     and LINK_COST_ZERO.  */  if (LINK_COST_FREE (link))    cost = 1;#ifdef ADJUST_COST  else if (! LINK_COST_ZERO (link))    {      int ncost = cost;      ADJUST_COST (used, link, insn, ncost);      if (ncost <= 1)	LINK_COST_FREE (link) = ncost = 1;      if (cost == ncost)	LINK_COST_ZERO (link) = 1;      cost = ncost;    }#endif  return cost;}/* Compute the priority number for INSN.  */static intpriority (insn)     rtx insn;{  if (insn && GET_RTX_CLASS (GET_CODE (insn)) == 'i')    {      int prev_priority;      int max_priority;      int this_priority = INSN_PRIORITY (insn);      rtx prev;      if (this_priority > 0)	return this_priority;      max_priority = 1;      /* Nonzero if these insns must be scheduled together.  */      if (SCHED_GROUP_P (insn))	{	  prev = insn;	  while (SCHED_GROUP_P (prev))	    {	      prev = PREV_INSN (prev);	      INSN_REF_COUNT (prev) += 1;	    }	}      for (prev = LOG_LINKS (insn); prev; prev = XEXP (prev, 1))	{	  rtx x = XEXP (prev, 0);	  /* If this was a duplicate of a dependence we already deleted,	     ignore it.  */	  if (RTX_INTEGRATED_P (prev))	    continue;	  /* A dependence pointing to a note or deleted insn is always	     obsolete, because sched_analyze_insn will have created any	     necessary new dependences which replace it.  Notes and deleted	     insns can be created when instructions are deleted by insn	     splitting, or by register allocation.  */	  if (GET_CODE (x) == NOTE || INSN_DELETED_P (x))	    {	      remove_dependence (insn, x);	      continue;	    }	  /* Clear the link cost adjustment bits.  */	  LINK_COST_FREE (prev) = 0;#ifdef ADJUST_COST	  LINK_COST_ZERO (prev) = 0;#endif	  /* This priority calculation was chosen because it results in the	     least instruction movement, and does not hurt the performance	     of the resulting code compared to the old algorithm.	     This makes the sched algorithm more stable, which results	     in better code, because there is less register pressure,	     cross jumping is more likely to work, and debugging is easier.	     When all instructions have a latency of 1, there is no need to	     move any instructions.  Subtracting one here ensures that in such	     cases all instructions will end up with a priority of one, and	     hence no scheduling will be done.	     The original code did not subtract the one, and added the	     insn_cost of the current instruction to its priority (e.g.	     move the insn_cost call down to the end).  */	  prev_priority = priority (x) + insn_cost (x, prev, insn) - 1;	  if (prev_priority > max_priority)	    max_priority = prev_priority;	  INSN_REF_COUNT (x) += 1;	}      prepare_unit (insn_unit (insn));      INSN_PRIORITY (insn) = max_priority;      return INSN_PRIORITY (insn);    }  return 0;}/* Remove all INSN_LISTs and EXPR_LISTs from the pending lists and add   them to the unused_*_list variables, so that they can be reused.  */static voidfree_pending_lists (){  register rtx link, prev_link;  if (pending_read_insns)    {      prev_link = pending_read_insns;      link = XEXP (prev_link, 1);      while (link)	{	  prev_link = link;	  link = XEXP (link, 1);	}      XEXP (prev_link, 1) = unused_insn_list;      unused_insn_list = pending_read_insns;      pending_read_insns = 0;    }  if (pending_write_insns)    {      prev_link = pending_write_insns;      link = XEXP (prev_link, 1);      while (link)	{	  prev_link = link;	  link = XEXP (link, 1);	}      XEXP (prev_link, 1) = unused_insn_list;      unused_insn_list = pending_write_insns;      pending_write_insns = 0;    }  if (pending_read_mems)    {      prev_link = pending_read_mems;      link = XEXP (prev_link, 1);      while (link)	{	  prev_link = link;	  link = XEXP (link, 1);	}      XEXP (prev_link, 1) = unused_expr_list;      unused_expr_list = pending_read_mems;      pending_read_mems = 0;    }  if (pending_write_mems)    {      prev_link = pending_write_mems;      link = XEXP (prev_link, 1);      while (link)	{	  prev_link = link;	  link = XEXP (link, 1);	}      XEXP (prev_link, 1) = unused_expr_list;      unused_expr_list = pending_write_mems;      pending_write_mems = 0;    }}/* Add an INSN and MEM reference pair to a pending INSN_LIST and MEM_LIST.   The MEM is a memory reference contained within INSN, which we are saving   so that we can do memory aliasing on it.  */static voidadd_insn_mem_dependence (insn_list, mem_list, insn, mem)     rtx *insn_list, *mem_list, insn, mem;{  register rtx link;  if (unused_insn_list)    {      link = unused_insn_list;      unused_insn_list = XEXP (link, 1);    }  else    link = rtx_alloc (INSN_LIST);  XEXP (link, 0) = insn;  XEXP (link, 1) = *insn_list;  *insn_list = link;  if (unused_expr_list)    {      link = unused_expr_list;      unused_expr_list = XEXP (link, 1);    }  else    link = rtx_alloc (EXPR_LIST);  XEXP (link, 0) = mem;  XEXP (link, 1) = *mem_list;  *mem_list = link;  pending_lists_length++;}/* Make a dependency between every memory reference on the pending lists   and INSN, thus flushing the pending lists.  If ONLY_WRITE, don't flush

⌨️ 快捷键说明

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