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

📄 regclass.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
    }  else    {      warning ("unknown register name: %s", name);    }}/* Now the data and code for the `regclass' pass, which happens   just before local-alloc.  *//* The `costs' struct records the cost of using a hard register of each class   and of using memory for each pseudo.  We use this data to set up   register class preferences.  */struct costs{  int cost[N_REG_CLASSES];  int mem_cost;};/* Record the cost of each class for each pseudo.  */static struct costs *costs;/* Record the same data by operand number, accumulated for each alternative   in an insn.  The contribution to a pseudo is that of the minimum-cost   alternative.  */static struct costs op_costs[MAX_RECOG_OPERANDS];/* (enum reg_class) prefclass[R] is the preferred class for pseudo number R.   This is available after `regclass' is run.  */static char *prefclass;/* altclass[R] is a register class that we should use for allocating   pseudo number R if no register in the preferred class is available.   If no register in this class is available, memory is preferred.   It might appear to be more general to have a bitmask of classes here,   but since it is recommended that there be a class corresponding to the   union of most major pair of classes, that generality is not required.    This is available after `regclass' is run.  */static char *altclass;/* Record the depth of loops that we are in.  */static int loop_depth;/* Account for the fact that insns within a loop are executed very commonly,   but don't keep doing this as loops go too deep.  */static int loop_cost;static int copy_cost ();static void record_reg_classes ();static void record_address_regs ();/* Return the reg_class in which pseudo reg number REGNO is best allocated.   This function is sometimes called before the info has been computed.   When that happens, just return GENERAL_REGS, which is innocuous.  */enum reg_classreg_preferred_class (regno)     int regno;{  if (prefclass == 0)    return GENERAL_REGS;  return (enum reg_class) prefclass[regno];}enum reg_classreg_alternate_class (regno){  if (prefclass == 0)    return ALL_REGS;  return (enum reg_class) altclass[regno];}/* This prevents dump_flow_info from losing if called   before regclass is run.  */voidregclass_init (){  prefclass = 0;}/* This is a pass of the compiler that scans all instructions   and calculates the preferred class for each pseudo-register.   This information can be accessed later by calling `reg_preferred_class'.   This pass comes just before local register allocation.  */voidregclass (f, nregs)     rtx f;     int nregs;{#ifdef REGISTER_CONSTRAINTS  register rtx insn;  register int i, j;  struct costs init_cost;  rtx set;  int pass;  init_recog ();  costs = (struct costs *) alloca (nregs * sizeof (struct costs));#ifdef FORBIDDEN_INC_DEC_CLASSES  in_inc_dec = (char *) alloca (nregs);  /* Initialize information about which register classes can be used for     pseudos that are auto-incremented or auto-decremented.  It would     seem better to put this in init_reg_sets, but we need to be able     to allocate rtx, which we can't do that early.  */  for (i = 0; i < N_REG_CLASSES; i++)    {      rtx r = gen_rtx (REG, VOIDmode, 0);      enum machine_mode m;      for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)	if (TEST_HARD_REG_BIT (reg_class_contents[i], j))	  {	    REGNO (r) = j;	    for (m = VOIDmode; (int) m < (int) MAX_MACHINE_MODE;		 m = (enum machine_mode) ((int) m) + 1)	      if (HARD_REGNO_MODE_OK (j, m))		{		  PUT_MODE (r, m);		  if (0#ifdef SECONDARY_INPUT_RELOAD_CLASS		      || (SECONDARY_INPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)			  != NO_REGS)#endif#ifdef SECONDARY_OUTPUT_RELOAD_CLASS		      || (SECONDARY_OUTPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)			  != NO_REGS)#endif		      )		    forbidden_inc_dec_class[i] = 1;		}	  }    }#endif /* FORBIDDEN_INC_DEC_CLASSES */  init_cost.mem_cost = 10000;  for (i = 0; i < N_REG_CLASSES; i++)    init_cost.cost[i] = 10000;  /* Normally we scan the insns once and determine the best class to use for     each register.  However, if -fexpensive_optimizations are on, we do so     twice, the second time using the tentative best classes to guide the     selection.  */  for (pass = 0; pass <= flag_expensive_optimizations; pass++)    {      /* Zero out our accumulation of the cost of each class for each reg.  */      bzero (costs, nregs * sizeof (struct costs));#ifdef FORBIDDEN_INC_DEC_CLASSES      bzero (in_inc_dec, nregs);#endif      loop_depth = 0, loop_cost = 1;      /* Scan the instructions and record each time it would	 save code to put a certain register in a certain class.  */      for (insn = f; insn; insn = NEXT_INSN (insn))	{	  char *constraints[MAX_RECOG_OPERANDS];	  enum machine_mode modes[MAX_RECOG_OPERANDS];	  int nalternatives;	  int noperands;	  /* Show that an insn inside a loop is likely to be executed three	     times more than insns outside a loop.  This is much more agressive	     than the assumptions made elsewhere and is being tried as an	     experiment.  */	  if (GET_CODE (insn) == NOTE	      && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)	    loop_depth++, loop_cost = 1 << (2 * MIN (loop_depth, 5));	  else if (GET_CODE (insn) == NOTE		   && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)	    loop_depth--, loop_cost = 1 << (2 * MIN (loop_depth, 5));	  else if ((GET_CODE (insn) == INSN		    && GET_CODE (PATTERN (insn)) != USE		    && GET_CODE (PATTERN (insn)) != CLOBBER		    && GET_CODE (PATTERN (insn)) != ASM_INPUT)		   || (GET_CODE (insn) == JUMP_INSN		       && GET_CODE (PATTERN (insn)) != ADDR_VEC		       && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)		   || GET_CODE (insn) == CALL_INSN)	    {	      if (GET_CODE (insn) == INSN		  && (noperands = asm_noperands (PATTERN (insn))) >= 0)		{		  decode_asm_operands (PATTERN (insn), recog_operand, NULL_PTR,				       constraints, modes);		  nalternatives = (noperands == 0 ? 0				   : n_occurrences (',', constraints[0]) + 1);		}	      else		{		  int insn_code_number = recog_memoized (insn);		  rtx note;		  set = single_set (insn);		  insn_extract (insn);		  nalternatives = insn_n_alternatives[insn_code_number];		  noperands = insn_n_operands[insn_code_number];		  /* If this insn loads a parameter from its stack slot, then		     it represents a savings, rather than a cost, if the		     parameter is stored in memory.  Record this fact.  */		  if (set != 0 && GET_CODE (SET_DEST (set)) == REG		      && GET_CODE (SET_SRC (set)) == MEM		      && (note = find_reg_note (insn, REG_EQUIV,						NULL_RTX)) != 0		      && GET_CODE (XEXP (note, 0)) == MEM)		    {		      costs[REGNO (SET_DEST (set))].mem_cost			-= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)))			    * loop_cost);		      record_address_regs (XEXP (SET_SRC (set), 0),					   BASE_REG_CLASS, loop_cost * 2);		      continue;		    }	      		  /* Improve handling of two-address insns such as		     (set X (ashift CONST Y)) where CONST must be made to		     match X. Change it into two insns: (set X CONST)		     (set X (ashift X Y)).  If we left this for reloading, it		     would probably get three insns because X and Y might go		     in the same place. This prevents X and Y from receiving		     the same hard reg.		     We can only do this if the modes of operands 0 and 1		     (which might not be the same) are tieable and we only need		     do this during our first pass.  */		  if (pass == 0 && optimize		      && noperands >= 3		      && insn_operand_constraint[insn_code_number][1][0] == '0'		      && insn_operand_constraint[insn_code_number][1][1] == 0		      && CONSTANT_P (recog_operand[1])		      && ! rtx_equal_p (recog_operand[0], recog_operand[1])		      && ! rtx_equal_p (recog_operand[0], recog_operand[2])		      && GET_CODE (recog_operand[0]) == REG		      && MODES_TIEABLE_P (GET_MODE (recog_operand[0]),					  insn_operand_mode[insn_code_number][1]))		    {		      rtx previnsn = prev_real_insn (insn);		      rtx dest			= gen_lowpart (insn_operand_mode[insn_code_number][1],				       recog_operand[0]);		      rtx newinsn			= emit_insn_before (gen_move_insn (dest,							   recog_operand[1]),					    insn);		      /* If this insn was the start of a basic block,			 include the new insn in that block.			 We need not check for code_label here;			 while a basic block can start with a code_label,			 INSN could not be at the beginning of that block.  */		      if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN)			{			  int b;			  for (b = 0; b < n_basic_blocks; b++)			    if (insn == basic_block_head[b])			      basic_block_head[b] = newinsn;			}		      /* This makes one more setting of new insns's dest. */		      reg_n_sets[REGNO (recog_operand[0])]++;		      *recog_operand_loc[1] = recog_operand[0];		      for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--)			if (recog_dup_num[i] == 1)			  *recog_dup_loc[i] = recog_operand[0];		      insn = PREV_INSN (newinsn);		      continue;		    }		  /* If this is setting a pseudo from another pseudo or the		     sum of a pseudo and a constant integer and the other		     pseudo is known to be a pointer, set the destination to		     be a pointer as well.		     Likewise if it is setting the destination from an address		     or from a value equivalent to an address or to the sum of		     an address and something else.		     		     But don't do any of this if the pseudo corresponds to		     a user variable since it should have already been set		     as a pointer based on the type.		     There is no point in doing this during our second		     pass since not enough should have changed.  */		  if (pass == 0 && set != 0 && GET_CODE (SET_DEST (set)) == REG		      && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER		      && ! REG_USERVAR_P (SET_DEST (set))		      && ! REGNO_POINTER_FLAG (REGNO (SET_DEST (set)))		      && ((GET_CODE (SET_SRC (set)) == REG			   && REGNO_POINTER_FLAG (REGNO (SET_SRC (set))))			  || ((GET_CODE (SET_SRC (set)) == PLUS			       || GET_CODE (SET_SRC (set)) == LO_SUM)			      && (GET_CODE (XEXP (SET_SRC (set), 1))				  == CONST_INT)			      && GET_CODE (XEXP (SET_SRC (set), 0)) == REG			      && REGNO_POINTER_FLAG (REGNO (XEXP (SET_SRC (set), 0))))			  || GET_CODE (SET_SRC (set)) == CONST			  || GET_CODE (SET_SRC (set)) == SYMBOL_REF			  || GET_CODE (SET_SRC (set)) == LABEL_REF			  || (GET_CODE (SET_SRC (set)) == HIGH			      && (GET_CODE (XEXP (SET_SRC (set), 0)) == CONST				  || (GET_CODE (XEXP (SET_SRC (set), 0))				      == SYMBOL_REF)				  || (GET_CODE (XEXP (SET_SRC (set), 0))				      == LABEL_REF)))			  || ((GET_CODE (SET_SRC (set)) == PLUS			       || GET_CODE (SET_SRC (set)) == LO_SUM)			      && (GET_CODE (XEXP (SET_SRC (set), 1)) == CONST				  || (GET_CODE (XEXP (SET_SRC (set), 1))				      == SYMBOL_REF)				  || (GET_CODE (XEXP (SET_SRC (set), 1))				      == LABEL_REF)))			  || ((note = find_reg_note (insn, REG_EQUAL, 0)) != 0			      && (GET_CODE (XEXP (note, 0)) == CONST				  || GET_CODE (XEXP (note, 0)) == SYMBOL_REF				  || GET_CODE (XEXP (note, 0)) == LABEL_REF))))		    REGNO_POINTER_FLAG (REGNO (SET_DEST (set))) = 1;		  for (i = 0; i < noperands; i++)		    {		      constraints[i]			= insn_operand_constraint[insn_code_number][i];		      modes[i] = insn_operand_mode[insn_code_number][i];		    }		}	      /* If we get here, we are set up to record the costs of all the		 operands for this insn.  Start by initializing the costs.		 Then handle any address registers.  Finally record the desired		 classes for any pseudos, doing it twice if some pair of		 operands are commutative.  */	     	      for (i = 0; i < noperands; i++)		{		  op_costs[i] = init_cost;		  if (GET_CODE (recog_operand[i]) == SUBREG)		    recog_operand[i] = SUBREG_REG (recog_operand[i]);		  if (GET_CODE (recog_operand[i]) == MEM)		    record_address_regs (XEXP (recog_operand[i], 0),					 BASE_REG_CLASS, loop_cost * 2);		  else if (constraints[i][0] == 'p')		    record_address_regs (recog_operand[i],					 BASE_REG_CLASS, loop_cost * 2);		}	      /* Check for commutative in a separate loop so everything will		 have been initialized.  Don't bother doing anything if the		 second operand is a constant since that is the case		 for which the constraints should have been written.  */	      	      for (i = 0; i < noperands - 1; i++)		if (constraints[i][0] == '%'		    && ! CONSTANT_P (recog_operand[i+1]))		  {		    char *xconstraints[MAX_RECOG_OPERANDS];		    int j;		    /* Handle commutative operands by swapping the constraints.		       We assume the modes are the same.  */		    for (j = 0; j < noperands; j++)		      xconstraints[j] = constraints[j];		    xconstraints[i] = constraints[i+1];		    xconstraints[i+1] = constraints[i];		    record_reg_classes (nalternatives, noperands,					recog_operand, modes, xconstraints,					insn);		  }	      record_reg_classes (nalternatives, noperands, recog_operand,				  modes, constraints, insn);	      /* Now add the cost for each operand to the total costs for		 its register.  */	      for (i = 0; i < noperands; i++)		if (GET_CODE (recog_operand[i]) == REG		    && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER)		  {		    int regno = REGNO (recog_operand[i]);		    struct costs *p = &costs[regno], *q = &op_costs[i];		    p->mem_cost += q->mem_cost * loop_cost;		    for (j = 0; j < N_REG_CLASSES; j++)		      p->cost[j] += q->cost[j] * loop_cost;		  }	    }	}

⌨️ 快捷键说明

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