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

📄 regclass.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 4 页
字号:
   It should be a fixed register if FIXED and a   call-used register if CALL_USED.  */voidfix_register (name, fixed, call_used)     char *name;     int fixed, call_used;{  int i;  if (output_bytecode)    {      warning ("request to mark `%s' as %s ignored by bytecode compiler",	       name, call_used ? "call-used" : "fixed");      return;    }  /* Decode the name and update the primary form of     the register info.  */  if ((i = decode_reg_name (name)) >= 0)    {      fixed_regs[i] = fixed;      call_used_regs[i] = call_used;    }  else    {      warning ("unknown register name: %s", name);    }}/* Mark register number I as global.  */voidglobalize_reg (i)     int i;{  if (global_regs[i])    {      warning ("register used for two global register variables");      return;    }  if (call_used_regs[i] && ! fixed_regs[i])    warning ("call-clobbered register used for global register variable");  global_regs[i] = 1;  /* If already fixed, nothing else to do.  */  if (fixed_regs[i])    return;  fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 1;  n_non_fixed_regs--;  SET_HARD_REG_BIT (fixed_reg_set, i);  SET_HARD_REG_BIT (call_used_reg_set, i);  SET_HARD_REG_BIT (call_fixed_reg_set, i);}/* 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 void record_reg_classes	PROTO((int, int, rtx *, enum machine_mode *,				       char **, rtx));static int copy_cost		PROTO((rtx, enum machine_mode, 				       enum reg_class, int));static void record_address_regs	PROTO((rtx, enum reg_class, int));static auto_inc_dec_reg_p	PROTO((rtx, enum machine_mode));static void reg_scan_mark_refs	PROTO((rtx, rtx, int));/* 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 a register is not directly suitable for an		     auto-increment or decrement addressing mode and		     requires secondary reloads, disallow its class from		     being used in such addresses.  */		  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		       )		      && ! auto_inc_dec_reg_p (r, m))		    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 ((char *) 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 aggressive	     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;		    }		  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.  We must do this even if one operand		 is a constant--see addsi3 in m68k.md.  */	      	      for (i = 0; i < noperands - 1; i++)		if (constraints[i][0] == '%')		  {		    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;		  }	    }	}      /* Now for each register look at how desirable each class is	 and find which class is preferred.  Store that in	 `prefclass[REGNO]'.  Record in `altclass[REGNO]' the largest register	 class any of whose registers is better than memory.  */          if (pass == 0)	{	  prefclass = (char *) oballoc (nregs);	  altclass = (char *) oballoc (nregs);	}      for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)	{	  register int best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1;	  enum reg_class best = ALL_REGS, alt = NO_REGS;	  /* This is an enum reg_class, but we call it an int	     to save lots of casts.  */	  register int class;	  register struct costs *p = &costs[i];	  for (class = (int) ALL_REGS - 1; class > 0; class--)	    {	      /* Ignore classes that are too small for this operand or		 invalid for a operand that was auto-incremented.  */	      if (CLASS_MAX_NREGS (class, PSEUDO_REGNO_MODE (i))		  > reg_class_size[class]#ifdef FORBIDDEN_INC_DEC_CLASSES		  || (in_inc_dec[i] && forbidden_inc_dec_class[class])#endif		  )		;	      else if (p->cost[class] < best_cost)		{		  best_cost = p->cost[class];		  best = (enum reg_class) class;		}	      else if (p->cost[class] == best_cost)		best = reg_class_subunion[(int)best][class];	    }	  /* Record the alternate register class; i.e., a class for which	     every register in it is better than using memory.  If adding a

⌨️ 快捷键说明

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