sched.c

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

C
2,054
字号
   the read list.  */static voidflush_pending_lists (insn, only_write)     rtx insn;     int only_write;{  rtx link;  while (pending_read_insns && ! only_write)    {      add_dependence (insn, XEXP (pending_read_insns, 0), REG_DEP_ANTI);      link = pending_read_insns;      pending_read_insns = XEXP (pending_read_insns, 1);      XEXP (link, 1) = unused_insn_list;      unused_insn_list = link;      link = pending_read_mems;      pending_read_mems = XEXP (pending_read_mems, 1);      XEXP (link, 1) = unused_expr_list;      unused_expr_list = link;    }  while (pending_write_insns)    {      add_dependence (insn, XEXP (pending_write_insns, 0), REG_DEP_ANTI);      link = pending_write_insns;      pending_write_insns = XEXP (pending_write_insns, 1);      XEXP (link, 1) = unused_insn_list;      unused_insn_list = link;      link = pending_write_mems;      pending_write_mems = XEXP (pending_write_mems, 1);      XEXP (link, 1) = unused_expr_list;      unused_expr_list = link;    }  pending_lists_length = 0;  if (last_pending_memory_flush)    add_dependence (insn, last_pending_memory_flush, REG_DEP_ANTI);  last_pending_memory_flush = insn;}/* Analyze a single SET or CLOBBER rtx, X, creating all dependencies generated   by the write to the destination of X, and reads of everything mentioned.  */static voidsched_analyze_1 (x, insn)     rtx x;     rtx insn;{  register int regno;  register rtx dest = SET_DEST (x);  if (dest == 0)    return;  while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG	 || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)    {      if (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)	{	  /* The second and third arguments are values read by this insn.  */	  sched_analyze_2 (XEXP (dest, 1), insn);	  sched_analyze_2 (XEXP (dest, 2), insn);	}      dest = SUBREG_REG (dest);    }  if (GET_CODE (dest) == REG)    {      register int i;      regno = REGNO (dest);      /* A hard reg in a wide mode may really be multiple registers.	 If so, mark all of them just like the first.  */      if (regno < FIRST_PSEUDO_REGISTER)	{	  i = HARD_REGNO_NREGS (regno, GET_MODE (dest));	  while (--i >= 0)	    {	      rtx u;	      for (u = reg_last_uses[regno+i]; u; u = XEXP (u, 1))		add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);	      reg_last_uses[regno + i] = 0;	      if (reg_last_sets[regno + i])		add_dependence (insn, reg_last_sets[regno + i],				REG_DEP_OUTPUT);	      SET_REGNO_REG_SET (reg_pending_sets, regno + i);	      if ((call_used_regs[i] || global_regs[i])		  && last_function_call)		/* Function calls clobber all call_used regs.  */		add_dependence (insn, last_function_call, REG_DEP_ANTI);	    }	}      else	{	  rtx u;	  for (u = reg_last_uses[regno]; u; u = XEXP (u, 1))	    add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);	  reg_last_uses[regno] = 0;	  if (reg_last_sets[regno])	    add_dependence (insn, reg_last_sets[regno], REG_DEP_OUTPUT);	  SET_REGNO_REG_SET (reg_pending_sets, regno);	  /* Pseudos that are REG_EQUIV to something may be replaced	     by that during reloading.  We need only add dependencies for	     the address in the REG_EQUIV note.  */	  if (! reload_completed	      && reg_known_equiv_p[regno]	      && GET_CODE (reg_known_value[regno]) == MEM)	    sched_analyze_2 (XEXP (reg_known_value[regno], 0), insn);	  /* Don't let it cross a call after scheduling if it doesn't	     already cross one.  */	  if (REG_N_CALLS_CROSSED (regno) == 0 && last_function_call)	    add_dependence (insn, last_function_call, REG_DEP_ANTI);	}    }  else if (GET_CODE (dest) == MEM)    {      /* Writing memory.  */      if (pending_lists_length > 32)	{	  /* Flush all pending reads and writes to prevent the pending lists	     from getting any larger.  Insn scheduling runs too slowly when	     these lists get long.  The number 32 was chosen because it	     seems like a reasonable number.  When compiling GCC with itself,	     this flush occurs 8 times for sparc, and 10 times for m88k using	     the number 32.  */	  flush_pending_lists (insn, 0);	}      else	{	  rtx pending, pending_mem;	  pending = pending_read_insns;	  pending_mem = pending_read_mems;	  while (pending)	    {	      /* If a dependency already exists, don't create a new one.  */	      if (! find_insn_list (XEXP (pending, 0), LOG_LINKS (insn)))		if (anti_dependence (XEXP (pending_mem, 0), dest))		  add_dependence (insn, XEXP (pending, 0), REG_DEP_ANTI);	      pending = XEXP (pending, 1);	      pending_mem = XEXP (pending_mem, 1);	    }	  pending = pending_write_insns;	  pending_mem = pending_write_mems;	  while (pending)	    {	      /* If a dependency already exists, don't create a new one.  */	      if (! find_insn_list (XEXP (pending, 0), LOG_LINKS (insn)))		if (output_dependence (XEXP (pending_mem, 0), dest))		  add_dependence (insn, XEXP (pending, 0), REG_DEP_OUTPUT);	      pending = XEXP (pending, 1);	      pending_mem = XEXP (pending_mem, 1);	    }	  if (last_pending_memory_flush)	    add_dependence (insn, last_pending_memory_flush, REG_DEP_ANTI);	  add_insn_mem_dependence (&pending_write_insns, &pending_write_mems,				   insn, dest);	}      sched_analyze_2 (XEXP (dest, 0), insn);    }  /* Analyze reads.  */  if (GET_CODE (x) == SET)    sched_analyze_2 (SET_SRC (x), insn);}/* Analyze the uses of memory and registers in rtx X in INSN.  */static voidsched_analyze_2 (x, insn)     rtx x;     rtx insn;{  register int i;  register int j;  register enum rtx_code code;  register char *fmt;  if (x == 0)    return;  code = GET_CODE (x);  switch (code)    {    case CONST_INT:    case CONST_DOUBLE:    case SYMBOL_REF:    case CONST:    case LABEL_REF:      /* Ignore constants.  Note that we must handle CONST_DOUBLE here	 because it may have a cc0_rtx in its CONST_DOUBLE_CHAIN field, but	 this does not mean that this insn is using cc0.  */      return;#ifdef HAVE_cc0    case CC0:      {	rtx link, prev;	/* User of CC0 depends on immediately preceding insn.  */	SCHED_GROUP_P (insn) = 1;	/* There may be a note before this insn now, but all notes will	   be removed before we actually try to schedule the insns, so	   it won't cause a problem later.  We must avoid it here though.  */	prev = prev_nonnote_insn (insn);	/* Make a copy of all dependencies on the immediately previous insn,	   and add to this insn.  This is so that all the dependencies will	   apply to the group.  Remove an explicit dependence on this insn	   as SCHED_GROUP_P now represents it.  */	if (find_insn_list (prev, LOG_LINKS (insn)))	  remove_dependence (insn, prev);	for (link = LOG_LINKS (prev); link; link = XEXP (link, 1))	  add_dependence (insn, XEXP (link, 0), REG_NOTE_KIND (link));	return;      }#endif    case REG:      {	int regno = REGNO (x);	if (regno < FIRST_PSEUDO_REGISTER)	  {	    int i;	    i = HARD_REGNO_NREGS (regno, GET_MODE (x));	    while (--i >= 0)	      {		reg_last_uses[regno + i]		  = gen_rtx (INSN_LIST, VOIDmode,			     insn, reg_last_uses[regno + i]);		if (reg_last_sets[regno + i])		  add_dependence (insn, reg_last_sets[regno + i], 0);		if ((call_used_regs[regno + i] || global_regs[regno + i])		    && last_function_call)		  /* Function calls clobber all call_used regs.  */		  add_dependence (insn, last_function_call, REG_DEP_ANTI);	      }	  }	else	  {	    reg_last_uses[regno]	      = gen_rtx (INSN_LIST, VOIDmode, insn, reg_last_uses[regno]);	    if (reg_last_sets[regno])	      add_dependence (insn, reg_last_sets[regno], 0);	    /* Pseudos that are REG_EQUIV to something may be replaced	       by that during reloading.  We need only add dependencies for	       the address in the REG_EQUIV note.  */	    if (! reload_completed		&& reg_known_equiv_p[regno]		&& GET_CODE (reg_known_value[regno]) == MEM)	      sched_analyze_2 (XEXP (reg_known_value[regno], 0), insn);	    /* If the register does not already cross any calls, then add this	       insn to the sched_before_next_call list so that it will still	       not cross calls after scheduling.  */	    if (REG_N_CALLS_CROSSED (regno) == 0)	      add_dependence (sched_before_next_call, insn, REG_DEP_ANTI);	  }	return;      }    case MEM:      {	/* Reading memory.  */	rtx pending, pending_mem;	pending = pending_read_insns;	pending_mem = pending_read_mems;	while (pending)	  {	    /* If a dependency already exists, don't create a new one.  */	    if (! find_insn_list (XEXP (pending, 0), LOG_LINKS (insn)))	      if (read_dependence (XEXP (pending_mem, 0), x))		add_dependence (insn, XEXP (pending, 0), REG_DEP_ANTI);	    pending = XEXP (pending, 1);	    pending_mem = XEXP (pending_mem, 1);	  }	pending = pending_write_insns;	pending_mem = pending_write_mems;	while (pending)	  {	    /* If a dependency already exists, don't create a new one.  */	    if (! find_insn_list (XEXP (pending, 0), LOG_LINKS (insn)))	      if (true_dependence (XEXP (pending_mem, 0), x))		add_dependence (insn, XEXP (pending, 0), 0);	    pending = XEXP (pending, 1);	    pending_mem = XEXP (pending_mem, 1);	  }	if (last_pending_memory_flush)	  add_dependence (insn, last_pending_memory_flush, REG_DEP_ANTI);	/* Always add these dependencies to pending_reads, since	   this insn may be followed by a write.  */	add_insn_mem_dependence (&pending_read_insns, &pending_read_mems,				 insn, x);	/* Take advantage of tail recursion here.  */	sched_analyze_2 (XEXP (x, 0), insn);	return;      }    case ASM_OPERANDS:    case ASM_INPUT:    case UNSPEC_VOLATILE:    case TRAP_IF:      {	rtx u;	/* Traditional and volatile asm instructions must be considered to use	   and clobber all hard registers, all pseudo-registers and all of	   memory.  So must TRAP_IF and UNSPEC_VOLATILE operations.	   Consider for instance a volatile asm that changes the fpu rounding	   mode.  An insn should not be moved across this even if it only uses	   pseudo-regs because it might give an incorrectly rounded result.  */	if (code != ASM_OPERANDS || MEM_VOLATILE_P (x))	  {	    int max_reg = max_reg_num ();	    for (i = 0; i < max_reg; i++)	      {		for (u = reg_last_uses[i]; u; u = XEXP (u, 1))		  add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);		reg_last_uses[i] = 0;		if (reg_last_sets[i])		  add_dependence (insn, reg_last_sets[i], 0);	      }	    reg_pending_sets_all = 1;	    flush_pending_lists (insn, 0);	  }	/* For all ASM_OPERANDS, we must traverse the vector of input operands.	   We can not just fall through here since then we would be confused	   by the ASM_INPUT rtx inside ASM_OPERANDS, which do not indicate	   traditional asms unlike their normal usage.  */	if (code == ASM_OPERANDS)	  {	    for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++)	      sched_analyze_2 (ASM_OPERANDS_INPUT (x, j), insn);	    return;	  }	break;      }    case PRE_DEC:    case POST_DEC:    case PRE_INC:    case POST_INC:      /* These both read and modify the result.  We must handle them as writes	 to get proper dependencies for following instructions.  We must handle	 them as reads to get proper dependencies from this to previous	 instructions.  Thus we need to pass them to both sched_analyze_1	 and sched_analyze_2.  We must call sched_analyze_2 first in order	 to get the proper antecedent for the read.  */      sched_analyze_2 (XEXP (x, 0), insn);      sched_analyze_1 (x, insn);      return;          default:      break;    }  /* Other cases: walk the insn.  */  fmt = GET_RTX_FORMAT (code);  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)    {      if (fmt[i] == 'e')	sched_analyze_2 (XEXP (x, i), insn);      else if (fmt[i] == 'E')	for (j = 0; j < XVECLEN (x, i); j++)	  sched_analyze_2 (XVECEXP (x, i, j), insn);    }}/* Analyze an INSN with pattern X to find all dependencies.  */static voidsched_analyze_insn (x, insn, loop_notes)     rtx x, insn;     rtx loop_notes;{  register RTX_CODE cod

⌨️ 快捷键说明

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