reload.c

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

C
1,737
字号
static intpush_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,		       type, picode)     int in_p;     rtx x;     int opnum;     int optional;     enum reg_class reload_class;     enum machine_mode reload_mode;     enum reload_type type;     enum insn_code *picode;{  enum reg_class class = NO_REGS;  enum machine_mode mode = reload_mode;  enum insn_code icode = CODE_FOR_nothing;  enum reg_class t_class = NO_REGS;  enum machine_mode t_mode = VOIDmode;  enum insn_code t_icode = CODE_FOR_nothing;  enum reload_type secondary_type;  int i;  int s_reload, t_reload = -1;  if (type == RELOAD_FOR_INPUT_ADDRESS      || type == RELOAD_FOR_OUTPUT_ADDRESS      || type == RELOAD_FOR_INPADDR_ADDRESS      || type == RELOAD_FOR_OUTADDR_ADDRESS)    secondary_type = type;  else    secondary_type = in_p ? RELOAD_FOR_INPUT_ADDRESS : RELOAD_FOR_OUTPUT_ADDRESS;  *picode = CODE_FOR_nothing;  /* If X is a paradoxical SUBREG, use the inner value to determine both the     mode and object being reloaded.  */  if (GET_CODE (x) == SUBREG      && (GET_MODE_SIZE (GET_MODE (x))	  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))    {      x = SUBREG_REG (x);      reload_mode = GET_MODE (x);    }  /* If X is a pseudo-register that has an equivalent MEM (actually, if it     is still a pseudo-register by now, it *must* have an equivalent MEM     but we don't want to assume that), use that equivalent when seeing if     a secondary reload is needed since whether or not a reload is needed     might be sensitive to the form of the MEM.  */  if (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER      && reg_equiv_mem[REGNO (x)] != 0)    x = reg_equiv_mem[REGNO (x)];#ifdef SECONDARY_INPUT_RELOAD_CLASS  if (in_p)    class = SECONDARY_INPUT_RELOAD_CLASS (reload_class, reload_mode, x);#endif#ifdef SECONDARY_OUTPUT_RELOAD_CLASS  if (! in_p)    class = SECONDARY_OUTPUT_RELOAD_CLASS (reload_class, reload_mode, x);#endif  /* If we don't need any secondary registers, done.  */  if (class == NO_REGS)    return -1;  /* Get a possible insn to use.  If the predicate doesn't accept X, don't     use the insn.  */  icode = (in_p ? reload_in_optab[(int) reload_mode]	   : reload_out_optab[(int) reload_mode]);  if (icode != CODE_FOR_nothing      && insn_operand_predicate[(int) icode][in_p]      && (! (insn_operand_predicate[(int) icode][in_p]) (x, reload_mode)))    icode = CODE_FOR_nothing;  /* If we will be using an insn, see if it can directly handle the reload     register we will be using.  If it can, the secondary reload is for a     scratch register.  If it can't, we will use the secondary reload for     an intermediate register and require a tertiary reload for the scratch     register.  */  if (icode != CODE_FOR_nothing)    {      /* If IN_P is non-zero, the reload register will be the output in 	 operand 0.  If IN_P is zero, the reload register will be the input	 in operand 1.  Outputs should have an initial "=", which we must	 skip.  */      char insn_letter = insn_operand_constraint[(int) icode][!in_p][in_p];      enum reg_class insn_class	= (insn_letter == 'r' ? GENERAL_REGS	   : REG_CLASS_FROM_LETTER (insn_letter));      if (insn_class == NO_REGS	  || (in_p && insn_operand_constraint[(int) icode][!in_p][0] != '=')	  /* The scratch register's constraint must start with "=&".  */	  || insn_operand_constraint[(int) icode][2][0] != '='	  || insn_operand_constraint[(int) icode][2][1] != '&')	abort ();      if (reg_class_subset_p (reload_class, insn_class))	mode = insn_operand_mode[(int) icode][2];      else	{	  char t_letter = insn_operand_constraint[(int) icode][2][2];	  class = insn_class;	  t_mode = insn_operand_mode[(int) icode][2];	  t_class = (t_letter == 'r' ? GENERAL_REGS		     : REG_CLASS_FROM_LETTER (t_letter));	  t_icode = icode;	  icode = CODE_FOR_nothing;	}    }  /* This case isn't valid, so fail.  Reload is allowed to use the same     register for RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_INPUT reloads, but     in the case of a secondary register, we actually need two different     registers for correct code.  We fail here to prevent the possibility of     silently generating incorrect code later.     The convention is that secondary input reloads are valid only if the     secondary_class is different from class.  If you have such a case, you     can not use secondary reloads, you must work around the problem some     other way.     Allow this when MODE is not reload_mode and assume that the generated     code handles this case (it does on the Alpha, which is the only place     this currently happens).  */  if (in_p && class == reload_class && mode == reload_mode)    abort ();  /* If we need a tertiary reload, see if we have one we can reuse or else     make a new one.  */  if (t_class != NO_REGS)    {      for (t_reload = 0; t_reload < n_reloads; t_reload++)	if (reload_secondary_p[t_reload]	    && (reg_class_subset_p (t_class, reload_reg_class[t_reload])		|| reg_class_subset_p (reload_reg_class[t_reload], t_class))	    && ((in_p && reload_inmode[t_reload] == t_mode)		|| (! in_p && reload_outmode[t_reload] == t_mode))	    && ((in_p && (reload_secondary_in_icode[t_reload]			  == CODE_FOR_nothing))		|| (! in_p &&(reload_secondary_out_icode[t_reload]			      == CODE_FOR_nothing)))	    && (reg_class_size[(int) t_class] == 1 || SMALL_REGISTER_CLASSES)	    && MERGABLE_RELOADS (secondary_type,				 reload_when_needed[t_reload],				 opnum, reload_opnum[t_reload]))	  {	    if (in_p)	      reload_inmode[t_reload] = t_mode;	    if (! in_p)	      reload_outmode[t_reload] = t_mode;	    if (reg_class_subset_p (t_class, reload_reg_class[t_reload]))	      reload_reg_class[t_reload] = t_class;	    reload_opnum[t_reload] = MIN (reload_opnum[t_reload], opnum);	    reload_optional[t_reload] &= optional;	    reload_secondary_p[t_reload] = 1;	    if (MERGE_TO_OTHER (secondary_type, reload_when_needed[t_reload],				opnum, reload_opnum[t_reload]))	      reload_when_needed[t_reload] = RELOAD_OTHER;	  }      if (t_reload == n_reloads)	{	  /* We need to make a new tertiary reload for this register class.  */	  reload_in[t_reload] = reload_out[t_reload] = 0;	  reload_reg_class[t_reload] = t_class;	  reload_inmode[t_reload] = in_p ? t_mode : VOIDmode;	  reload_outmode[t_reload] = ! in_p ? t_mode : VOIDmode;	  reload_reg_rtx[t_reload] = 0;	  reload_optional[t_reload] = optional;	  reload_inc[t_reload] = 0;	  /* Maybe we could combine these, but it seems too tricky.  */	  reload_nocombine[t_reload] = 1;	  reload_in_reg[t_reload] = 0;	  reload_opnum[t_reload] = opnum;	  reload_when_needed[t_reload] = secondary_type;	  reload_secondary_in_reload[t_reload] = -1;	  reload_secondary_out_reload[t_reload] = -1;	  reload_secondary_in_icode[t_reload] = CODE_FOR_nothing;	  reload_secondary_out_icode[t_reload] = CODE_FOR_nothing;	  reload_secondary_p[t_reload] = 1;	  n_reloads++;	}    }  /* See if we can reuse an existing secondary reload.  */  for (s_reload = 0; s_reload < n_reloads; s_reload++)    if (reload_secondary_p[s_reload]	&& (reg_class_subset_p (class, reload_reg_class[s_reload])	    || reg_class_subset_p (reload_reg_class[s_reload], class))	&& ((in_p && reload_inmode[s_reload] == mode)	    || (! in_p && reload_outmode[s_reload] == mode))	&& ((in_p && reload_secondary_in_reload[s_reload] == t_reload)	    || (! in_p && reload_secondary_out_reload[s_reload] == t_reload))	&& ((in_p && reload_secondary_in_icode[s_reload] == t_icode)	    || (! in_p && reload_secondary_out_icode[s_reload] == t_icode))	&& (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)	&& MERGABLE_RELOADS (secondary_type, reload_when_needed[s_reload],			     opnum, reload_opnum[s_reload]))      {	if (in_p)	  reload_inmode[s_reload] = mode;	if (! in_p)	  reload_outmode[s_reload] = mode;	if (reg_class_subset_p (class, reload_reg_class[s_reload]))	  reload_reg_class[s_reload] = class;	reload_opnum[s_reload] = MIN (reload_opnum[s_reload], opnum);	reload_optional[s_reload] &= optional;	reload_secondary_p[s_reload] = 1;	if (MERGE_TO_OTHER (secondary_type, reload_when_needed[s_reload],			    opnum, reload_opnum[s_reload]))	  reload_when_needed[s_reload] = RELOAD_OTHER;      }  if (s_reload == n_reloads)    {#ifdef SECONDARY_MEMORY_NEEDED      /* If we need a memory location to copy between the two reload regs,	 set it up now.  Note that we do the input case before making	 the reload and the output case after.  This is due to the 	 way reloads are output.  */      if (in_p && icode == CODE_FOR_nothing	  && SECONDARY_MEMORY_NEEDED (class, reload_class, mode))	get_secondary_mem (x, reload_mode, opnum, type);#endif      /* We need to make a new secondary reload for this register class.  */      reload_in[s_reload] = reload_out[s_reload] = 0;      reload_reg_class[s_reload] = class;      reload_inmode[s_reload] = in_p ? mode : VOIDmode;      reload_outmode[s_reload] = ! in_p ? mode : VOIDmode;      reload_reg_rtx[s_reload] = 0;      reload_optional[s_reload] = optional;      reload_inc[s_reload] = 0;      /* Maybe we could combine these, but it seems too tricky.  */      reload_nocombine[s_reload] = 1;      reload_in_reg[s_reload] = 0;      reload_opnum[s_reload] = opnum;      reload_when_needed[s_reload] = secondary_type;      reload_secondary_in_reload[s_reload] = in_p ? t_reload : -1;      reload_secondary_out_reload[s_reload] = ! in_p ? t_reload : -1;      reload_secondary_in_icode[s_reload] = in_p ? t_icode : CODE_FOR_nothing;       reload_secondary_out_icode[s_reload]	= ! in_p ? t_icode : CODE_FOR_nothing;      reload_secondary_p[s_reload] = 1;      n_reloads++;#ifdef SECONDARY_MEMORY_NEEDED      if (! in_p && icode == CODE_FOR_nothing	  && SECONDARY_MEMORY_NEEDED (reload_class, class, mode))	get_secondary_mem (x, mode, opnum, type);#endif    }  *picode = icode;  return s_reload;}#endif /* HAVE_SECONDARY_RELOADS */#ifdef SECONDARY_MEMORY_NEEDED/* Return a memory location that will be used to copy X in mode MODE.     If we haven't already made a location for this mode in this insn,   call find_reloads_address on the location being returned.  */rtxget_secondary_mem (x, mode, opnum, type)     rtx x;     enum machine_mode mode;     int opnum;     enum reload_type type;{  rtx loc;  int mem_valid;  /* By default, if MODE is narrower than a word, widen it to a word.     This is required because most machines that require these memory     locations do not support short load and stores from all registers     (e.g., FP registers).  */#ifdef SECONDARY_MEMORY_NEEDED_MODE  mode = SECONDARY_MEMORY_NEEDED_MODE (mode);#else  if (GET_MODE_BITSIZE (mode) < BITS_PER_WORD)    mode = mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (mode), 0);#endif  /* If we already have made a MEM for this operand in MODE, return it.  */  if (secondary_memlocs_elim[(int) mode][opnum] != 0)    return secondary_memlocs_elim[(int) mode][opnum];  /* If this is the first time we've tried to get a MEM for this mode,      allocate a new one.  `something_changed' in reload will get set     by noticing that the frame size has changed.  */  if (secondary_memlocs[(int) mode] == 0)    {#ifdef SECONDARY_MEMORY_NEEDED_RTX      secondary_memlocs[(int) mode] = SECONDARY_MEMORY_NEEDED_RTX (mode);#else      secondary_memlocs[(int) mode]	= assign_stack_local (mode, GET_MODE_SIZE (mode), 0);#endif    }  /* Get a version of the address doing any eliminations needed.  If that     didn't give us a new MEM, make a new one if it isn't valid.  */  loc = eliminate_regs (secondary_memlocs[(int) mode], VOIDmode, NULL_RTX, 0);  mem_valid = strict_memory_address_p (mode, XEXP (loc, 0));  if (! mem_valid && loc == secondary_memlocs[(int) mode])    loc = copy_rtx (loc);  /* The only time the call below will do anything is if the stack     offset is too large.  In that case IND_LEVELS doesn't matter, so we     can just pass a zero.  Adjust the type to be the address of the     corresponding object.  If the address was valid, save the eliminated     address.  If it wasn't valid, we need to make a reload each time, so     don't save it.  */  if (! mem_valid)    {      type =  (type == RELOAD_FOR_INPUT ? RELOAD_FOR_INPUT_ADDRESS	       : type == RELOAD_FOR_OUTPUT ? RELOAD_FOR_OUTPUT_ADDRESS	       : RELOAD_OTHER);      find_reloads_address (mode, NULL_PTR, XEXP (loc, 0), &XEXP (loc, 0),			    opnum, type, 0, 0);    }  secondary_memlocs_elim[(int) mode][opnum] = loc;

⌨️ 快捷键说明

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