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

📄 reload.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
  *ptertiary_icode = t_icode;  return class;}#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)     rtx x;     enum machine_mode mode;{  rtx loc;  int mem_valid;  /* If MODE is narrower than a word, widen it.  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).  We could     possibly conditionalize this, but we lose nothing by doing the wider     mode.  */  if (GET_MODE_BITSIZE (mode) < BITS_PER_WORD)    mode = mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (mode), 0);  /* If we already have made a MEM for this insn, return it.  */  if (secondary_memlocs_elim[(int) mode] != 0)    return secondary_memlocs_elim[(int) mode];  /* 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)    secondary_memlocs[(int) mode]      = assign_stack_local (mode, GET_MODE_SIZE (mode), 0);  /* 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], 0, NULL_RTX);  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.  */  if (! mem_valid)    find_reloads_address (mode, NULL_PTR, XEXP (loc, 0), &XEXP (loc, 0), x, 0);  /* If the address was not valid to begin with, we can not save it, because     there is no guarantee that the reloads needed to make it valid will     occur before every use of this address.  */  else    secondary_memlocs_elim[(int) mode] = loc;  return loc;}/* Clear any secondary memory locations we've made.  */voidclear_secondary_mem (){  int i;  for (i = 0; i < NUM_MACHINE_MODES; i++)    secondary_memlocs[i] = 0;}#endif /* SECONDARY_MEMORY_NEEDED *//* Record one (sometimes two) reload that needs to be performed.   IN is an rtx saying where the data are to be found before this instruction.   OUT says where they must be stored after the instruction.   (IN is zero for data not read, and OUT is zero for data not written.)   INLOC and OUTLOC point to the places in the instructions where   IN and OUT were found.   CLASS is a register class required for the reloaded data.   INMODE is the machine mode that the instruction requires   for the reg that replaces IN and OUTMODE is likewise for OUT.   If IN is zero, then OUT's location and mode should be passed as   INLOC and INMODE.   STRICT_LOW is the 1 if there is a containing STRICT_LOW_PART rtx.   OPTIONAL nonzero means this reload does not need to be performed:   it can be discarded if that is more convenient.   The return value is the reload-number for this reload.   If both IN and OUT are nonzero, in some rare cases we might   want to make two separate reloads.  (Actually we never do this now.)   Therefore, the reload-number for OUT is stored in   output_reloadnum when we return; the return value applies to IN.   Usually (presently always), when IN and OUT are nonzero,   the two reload-numbers are equal, but the caller should be careful to   distinguish them.  */static intpush_reload (in, out, inloc, outloc, class,	     inmode, outmode, strict_low, optional, needed_for)     register rtx in, out;     rtx *inloc, *outloc;     enum reg_class class;     enum machine_mode inmode, outmode;     int strict_low;     int optional;     rtx needed_for;{  register int i;  int dont_share = 0;  rtx *in_subreg_loc = 0, *out_subreg_loc = 0;  int secondary_reload = -1;  enum insn_code secondary_icode = CODE_FOR_nothing;  /* Compare two RTX's.  */#define MATCHES(x, y) \ (x == y || (x != 0 && (GET_CODE (x) == REG				\			? GET_CODE (y) == REG && REGNO (x) == REGNO (y)	\			: rtx_equal_p (x, y) && ! side_effects_p (x))))  /* INMODE and/or OUTMODE could be VOIDmode if no mode     has been specified for the operand.  In that case,     use the operand's mode as the mode to reload.  */  if (inmode == VOIDmode && in != 0)    inmode = GET_MODE (in);  if (outmode == VOIDmode && out != 0)    outmode = GET_MODE (out);  /* If IN is a pseudo register everywhere-equivalent to a constant, and      it is not in a hard register, reload straight from the constant,     since we want to get rid of such pseudo registers.     Often this is done earlier, but not always in find_reloads_address.  */  if (in != 0 && GET_CODE (in) == REG)    {      register int regno = REGNO (in);      if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0	  && reg_equiv_constant[regno] != 0)	in = reg_equiv_constant[regno];    }  /* Likewise for OUT.  Of course, OUT will never be equivalent to     an actual constant, but it might be equivalent to a memory location     (in the case of a parameter).  */  if (out != 0 && GET_CODE (out) == REG)    {      register int regno = REGNO (out);      if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0	  && reg_equiv_constant[regno] != 0)	out = reg_equiv_constant[regno];    }  /* If we have a read-write operand with an address side-effect,     change either IN or OUT so the side-effect happens only once.  */  if (in != 0 && out != 0 && GET_CODE (in) == MEM && rtx_equal_p (in, out))    {      if (GET_CODE (XEXP (in, 0)) == POST_INC	  || GET_CODE (XEXP (in, 0)) == POST_DEC)	in = gen_rtx (MEM, GET_MODE (in), XEXP (XEXP (in, 0), 0));      if (GET_CODE (XEXP (in, 0)) == PRE_INC	  || GET_CODE (XEXP (in, 0)) == PRE_DEC)	out = gen_rtx (MEM, GET_MODE (out), XEXP (XEXP (out, 0), 0));    }  /* If we are reloading a (SUBREG (MEM ...) ...) or (SUBREG constant ...),     really reload just the inside expression in its own mode.     If we have (SUBREG:M1 (REG:M2 ...) ...) with M1 wider than M2 and the     register is a pseudo, this will become the same as the above case.     Do the same for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where     either M1 is not valid for R or M2 is wider than a word but we only     need one word to store an M2-sized quantity in R.     Note that the case of (SUBREG (CONST_INT...)...) is handled elsewhere;     we can't handle it here because CONST_INT does not indicate a mode.     Similarly, we must reload the inside expression if we have a     STRICT_LOW_PART (presumably, in == out in the cas).     Also reload the inner expression if it does not require a secondary     reload but the SUBREG does.  */  if (in != 0 && GET_CODE (in) == SUBREG      && (GET_CODE (SUBREG_REG (in)) != REG	  || strict_low	  || (GET_CODE (SUBREG_REG (in)) == REG	      && REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER	      && (GET_MODE_SIZE (inmode)		  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))))	  || (GET_CODE (SUBREG_REG (in)) == REG	      && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER	      && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (in)), inmode)		  || (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD		      && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))			  > UNITS_PER_WORD)		      && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))			   / UNITS_PER_WORD)			  != HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)),					       GET_MODE (SUBREG_REG (in)))))))#ifdef SECONDARY_INPUT_RELOAD_CLASS	  || (SECONDARY_INPUT_RELOAD_CLASS (class, inmode, in) != NO_REGS	      && (SECONDARY_INPUT_RELOAD_CLASS (class,						GET_MODE (SUBREG_REG (in)),						SUBREG_REG (in))		  == NO_REGS))#endif	  ))    {      in_subreg_loc = inloc;      inloc = &SUBREG_REG (in);      in = *inloc;      if (GET_CODE (in) == MEM)	/* This is supposed to happen only for paradoxical subregs made by	   combine.c.  (SUBREG (MEM)) isn't supposed to occur other ways.  */	if (GET_MODE_SIZE (GET_MODE (in)) > GET_MODE_SIZE (inmode))	  abort ();      inmode = GET_MODE (in);    }  /* Similarly for paradoxical and problematical SUBREGs on the output.     Note that there is no reason we need worry about the previous value     of SUBREG_REG (out); even if wider than out,     storing in a subreg is entitled to clobber it all     (except in the case of STRICT_LOW_PART,     and in that case the constraint should label it input-output.)  */  if (out != 0 && GET_CODE (out) == SUBREG      && (GET_CODE (SUBREG_REG (out)) != REG	  || strict_low	  || (GET_CODE (SUBREG_REG (out)) == REG	      && REGNO (SUBREG_REG (out)) >= FIRST_PSEUDO_REGISTER	      && (GET_MODE_SIZE (outmode)		  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))))	  || (GET_CODE (SUBREG_REG (out)) == REG	      && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER	      && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (out)), outmode)		  || (GET_MODE_SIZE (outmode) <= UNITS_PER_WORD		      && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))			  > UNITS_PER_WORD)		      && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))			   / UNITS_PER_WORD)			  != HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)),					       GET_MODE (SUBREG_REG (out)))))))#ifdef SECONDARY_OUTPUT_RELOAD_CLASS	  || (SECONDARY_OUTPUT_RELOAD_CLASS (class, outmode, out) != NO_REGS	      && (SECONDARY_OUTPUT_RELOAD_CLASS (class,						 GET_MODE (SUBREG_REG (out)),						 SUBREG_REG (out))		  == NO_REGS))#endif	  ))    {      out_subreg_loc = outloc;      outloc = &SUBREG_REG (out);      out = *outloc;      if (GET_CODE (out) == MEM	  && GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode))	abort ();      outmode = GET_MODE (out);    }  /* That's all we use STRICT_LOW for, so clear it.  At some point,     we may want to get rid of reload_strict_low.  */  strict_low = 0;  /* If IN appears in OUT, we can't share any input-only reload for IN.  */  if (in != 0 && out != 0 && GET_CODE (out) == MEM      && (GET_CODE (in) == REG || GET_CODE (in) == MEM)      && reg_overlap_mentioned_for_reload_p (in, XEXP (out, 0)))    dont_share = 1;  /* If IN is a SUBREG of a hard register, make a new REG.  This     simplifies some of the cases below.  */  if (in != 0 && GET_CODE (in) == SUBREG && GET_CODE (SUBREG_REG (in)) == REG      && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER)    in = gen_rtx (REG, GET_MODE (in),		  REGNO (SUBREG_REG (in)) + SUBREG_WORD (in));  /* Similarly for OUT.  */  if (out != 0 && GET_CODE (out) == SUBREG      && GET_CODE (SUBREG_REG (out)) == REG      && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER)    out = gen_rtx (REG, GET_MODE (out),		  REGNO (SUBREG_REG (out)) + SUBREG_WORD (out));  /* Narrow down the class of register wanted if that is     desirable on this machine for efficiency.  */  if (in != 0)    class = PREFERRED_RELOAD_CLASS (in, class);  /* Output reloads may need analagous treatment, different in detail.  */#ifdef PREFERRED_OUTPUT_RELOAD_CLASS  if (out != 0)    class = PREFERRED_OUTPUT_RELOAD_CLASS (out, class);#endif  /* Make sure we use a class that can handle the actual pseudo     inside any subreg.  For example, on the 386, QImode regs     can appear within SImode subregs.  Although GENERAL_REGS     can handle SImode, QImode needs a smaller class.  */#ifdef LIMIT_RELOAD_CLASS  if (in_subreg_loc)    class = LIMIT_RELOAD_CLASS (inmode, class);  else if (in != 0 && GET_CODE (in) == SUBREG)    class = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (in)), class);  if (out_subreg_loc)    class = LIMIT_RELOAD_CLASS (outmode, class);  if (out != 0 && GET_CODE (out) == SUBREG)    class = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (out)), class);#endif  if (class == NO_REGS)    abort ();  /* Verify that this class is at least possible for the mode that     is specified.  */  if (this_insn_is_asm)    {      enum machine_mode mode;      if (GET_MODE_SIZE (inmode) > GET_MODE_SIZE (outmode))	mode = inmode;      else	mode = outmode;      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)	if (HARD_REGNO_MODE_OK (i, mode)	    && TEST_HARD_REG_BIT (reg_class_contents[(int) class], i))	  {	    int nregs = HARD_REGNO_NREGS (i, mode);	    int j;	    for (j = 1; j < nregs; j++)	      if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class], i + j))		break;	    if (j == nregs)	      break;	  }      if (i == FIRST_PSEUDO_REGISTER)	{	  error_for_asm (this_insn, "impossible register constraint in `asm'");	  class = ALL_REGS;	}    }  /* We can use an existing reload if the class is right     and at least one of IN and OUT is a match     and the other is at worst neutral.     (A zero compared against anything is neutral.)  */  for (i = 0; i < n_reloads; i++)    if ((reg_class_subset_p (class, reload_reg_class[i])	 || reg_class_subset_p (reload_reg_class[i], class))	&& reload_strict_low[i] == strict_low	/* If the existing reload has a register, it must fit our class.  */	&& (reload_reg_rtx[i] == 0	    || TEST_HARD_REG_BIT (reg_class_contents[(int) class],				  true_regnum (reload_reg_rtx[i])))	&& ((in != 0 && MATCHES (reload_in[i], in) && ! dont_share	     && (out == 0 || reload_out[i] == 0 || MATCHES (reload_out[i], out)))	    ||	    (out != 0 && MATCHES (reload_out[i], out)	     && (in == 0 || reload_in[i] == 0 || MATCHES (reload_in[i], in)))))      break;  /* Reloading a plain reg for input can match a reload to postincrement     that reg, since the postincrement's value is the right value.     Likewise, it can match a preincrement reload, since we regard     the preincrementation as happening before any ref in this insn     to that register.  */  if (i == n_reloads)

⌨️ 快捷键说明

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