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

📄 caller-save.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 2 页
字号:
		for (j = regno;		     j < regno + HARD_REGNO_NREGS (regno,						   PSEUDO_REGNO_MODE (i));		     j++)		  SET_HARD_REG_BIT (hard_regs_live, j);	}      /* Now scan the insns in the block, keeping track of what hard	 regs are live as we go.  When we see a call, save the live	 call-clobbered hard regs.  */      for (insn = basic_block_head[b]; ; insn = NEXT_INSN (insn))	{	  RTX_CODE code = GET_CODE (insn);	  if (GET_RTX_CLASS (code) == 'i')	    {	      rtx link;	      /* If some registers have been saved, see if INSN references		 any of them.  We must restore them before the insn if so.  */	      if (n_regs_saved)		restore_referenced_regs (PATTERN (insn), insn, insn_mode);	      /* NB: the normal procedure is to first enliven any		 registers set by insn, then deaden any registers that		 had their last use at insn.  This is incorrect now,		 since multiple pseudos may have been mapped to the		 same hard reg, and the death notes are ambiguous.  So		 it must be done in the other, safe, order.  */	      for (link = REG_NOTES (insn); link; link = XEXP (link, 1))		if (REG_NOTE_KIND (link) == REG_DEAD)		  clear_reg_live (XEXP (link, 0));	      /* When we reach a call, we need to save all registers that are		 live, call-used, not fixed, and not already saved.  We must		 test at this point because registers that die in a CALL_INSN		 are not live across the call and likewise for registers that		 are born in the CALL_INSN.		 		 If registers are filled with parameters for this function,		 and some of these are also being set by this function, then		 they will not appear to die (no REG_DEAD note for them),		 to check if in fact they do, collect the set registers in		 hard_regs_live first.  */	      if (code == CALL_INSN)		{		  HARD_REG_SET this_call_sets;		  {		    HARD_REG_SET old_hard_regs_live;		    /* Save the hard_regs_live information.  */		    COPY_HARD_REG_SET (old_hard_regs_live, hard_regs_live);		    /* Now calculate hard_regs_live for this CALL_INSN		       only.  */		    CLEAR_HARD_REG_SET (hard_regs_live);		    note_stores (PATTERN (insn), set_reg_live);		    COPY_HARD_REG_SET (this_call_sets, hard_regs_live);		    /* Restore the hard_regs_live information.  */		    COPY_HARD_REG_SET (hard_regs_live, old_hard_regs_live);		  }		  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)		    if (call_used_regs[regno] && ! call_fixed_regs[regno]		        && TEST_HARD_REG_BIT (hard_regs_live, regno)			/* It must not be set by this instruction.  */		        && ! TEST_HARD_REG_BIT (this_call_sets, regno)		        && ! TEST_HARD_REG_BIT (hard_regs_saved, regno))		      regno += insert_save_restore (insn, 1, regno, 						    insn_mode, 0);		  /* Put the information for this CALL_INSN on top of what		     we already had.  */		  IOR_HARD_REG_SET (hard_regs_live, this_call_sets);		  COPY_HARD_REG_SET (hard_regs_need_restore, hard_regs_saved);		  /* Must recompute n_regs_saved.  */		  n_regs_saved = 0;		  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)		    if (TEST_HARD_REG_BIT (hard_regs_saved, regno))		      n_regs_saved++;		}	      else		{		  note_stores (PATTERN (insn), set_reg_live);#ifdef AUTO_INC_DEC		  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))		    if (REG_NOTE_KIND (link) == REG_INC)		      set_reg_live (XEXP (link, 0), NULL_RTX);#endif		}	      for (link = REG_NOTES (insn); link; link = XEXP (link, 1))		if (REG_NOTE_KIND (link) == REG_UNUSED)		  clear_reg_live (XEXP (link, 0));	    }	  if (insn == basic_block_end[b])	    break;	}      /* At the end of the basic block, we must restore any registers that	 remain saved.  If the last insn in the block is a JUMP_INSN, put	 the restore before the insn, otherwise, put it after the insn.  */      if (n_regs_saved)	for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)	  if (TEST_HARD_REG_BIT (hard_regs_need_restore, regno))	    regno += insert_save_restore ((GET_CODE (insn) == JUMP_INSN				  ? insn : NEXT_INSN (insn)), 0,				  regno, insn_mode, MOVE_MAX / UNITS_PER_WORD);      /* If we added any insns at the start of the block, update the start	 of the block to point at those insns.  */      basic_block_head[b] = NEXT_INSN (prev_block_last);    }}/* Here from note_stores when an insn stores a value in a register.   Set the proper bit or bits in hard_regs_live.  All pseudos that have   been assigned hard regs have had their register number changed already,   so we can ignore pseudos.  */static voidset_reg_live (reg, setter)     rtx reg, setter;{  register int regno, endregno, i;  enum machine_mode mode = GET_MODE (reg);  int word = 0;  if (GET_CODE (reg) == SUBREG)    {      word = SUBREG_WORD (reg);      reg = SUBREG_REG (reg);    }  if (GET_CODE (reg) != REG || REGNO (reg) >= FIRST_PSEUDO_REGISTER)    return;  regno = REGNO (reg) + word;  endregno = regno + HARD_REGNO_NREGS (regno, mode);  for (i = regno; i < endregno; i++)    {      SET_HARD_REG_BIT (hard_regs_live, i);      CLEAR_HARD_REG_BIT (hard_regs_saved, i);      CLEAR_HARD_REG_BIT (hard_regs_need_restore, i);    }}/* Here when a REG_DEAD note records the last use of a reg.  Clear   the appropriate bit or bits in hard_regs_live.  Again we can ignore   pseudos.  */static voidclear_reg_live (reg)     rtx reg;{  register int regno, endregno, i;  if (GET_CODE (reg) != REG || REGNO (reg) >= FIRST_PSEUDO_REGISTER)    return;  regno = REGNO (reg);  endregno= regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));  for (i = regno; i < endregno; i++)    {      CLEAR_HARD_REG_BIT (hard_regs_live, i);      CLEAR_HARD_REG_BIT (hard_regs_need_restore, i);      CLEAR_HARD_REG_BIT (hard_regs_saved, i);    }}      /* If any register currently residing in the save area is referenced in X,   which is part of INSN, emit code to restore the register in front of INSN.   INSN_MODE is the mode to assign to any insns that we add.  */static voidrestore_referenced_regs (x, insn, insn_mode)     rtx x;     rtx insn;     enum machine_mode insn_mode;{  enum rtx_code code = GET_CODE (x);  char *fmt;  int i, j;  if (code == CLOBBER)    return;  if (code == REG)    {      int regno = REGNO (x);      /* If this is a pseudo, scan its memory location, since it might	 involve the use of another register, which might be saved.  */      if (regno >= FIRST_PSEUDO_REGISTER	  && reg_equiv_mem[regno] != 0)	restore_referenced_regs (XEXP (reg_equiv_mem[regno], 0),				 insn, insn_mode);      else if (regno >= FIRST_PSEUDO_REGISTER	       && reg_equiv_address[regno] != 0)	restore_referenced_regs (reg_equiv_address[regno],				 insn, insn_mode);      /* Otherwise if this is a hard register, restore any piece of it that	 is currently saved.  */      else if (regno < FIRST_PSEUDO_REGISTER)	{	  int numregs = HARD_REGNO_NREGS (regno, GET_MODE (x));	  /* Save at most SAVEREGS at a time.  This can not be larger than	     MOVE_MAX, because that causes insert_save_restore to fail.  */	  int saveregs = MIN (numregs, MOVE_MAX / UNITS_PER_WORD);	  int endregno = regno + numregs;	  for (i = regno; i < endregno; i++)	    if (TEST_HARD_REG_BIT (hard_regs_need_restore, i))	      i += insert_save_restore (insn, 0, i, insn_mode, saveregs);	}      return;    }	    fmt = GET_RTX_FORMAT (code);  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)    {      if (fmt[i] == 'e')	restore_referenced_regs (XEXP (x, i), insn, insn_mode);      else if (fmt[i] == 'E')	for (j = XVECLEN (x, i) - 1; j >= 0; j--)	  restore_referenced_regs (XVECEXP (x, i, j), insn, insn_mode);    }}/* Insert a sequence of insns to save or restore, SAVE_P says which,   REGNO.  Place these insns in front of INSN.  INSN_MODE is the mode   to assign to these insns.   MAXRESTORE is the maximum number of registers   which should be restored during this call (when SAVE_P == 0).  It should   never be less than 1 since we only work with entire registers.   Note that we have verified in init_caller_save that we can do this   with a simple SET, so use it.  Set INSN_CODE to what we save there   since the address might not be valid so the insn might not be recognized.   These insns will be reloaded and have register elimination done by   find_reload, so we need not worry about that here.   Return the extra number of registers saved.  */static intinsert_save_restore (insn, save_p, regno, insn_mode, maxrestore)     rtx insn;     int save_p;     int regno;     enum machine_mode insn_mode;     int maxrestore;{  rtx pat;  enum insn_code code;  int i, numregs;  /* A common failure mode if register status is not correct in the RTL     is for this routine to be called with a REGNO we didn't expect to     save.  That will cause us to write an insn with a (nil) SET_DEST     or SET_SRC.  Instead of doing so and causing a crash later, check     for this common case and abort here instead.  This will remove one     step in debugging such problems.  */  if (regno_save_mem[regno][1] == 0)    abort ();#ifdef HAVE_cc0  /* If INSN references CC0, put our insns in front of the insn that sets     CC0.  This is always safe, since the only way we could be passed an     insn that references CC0 is for a restore, and doing a restore earlier     isn't a problem.  We do, however, assume here that CALL_INSNs don't     reference CC0.  Guard against non-INSN's like CODE_LABEL.  */  if ((GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)      && reg_referenced_p (cc0_rtx, PATTERN (insn)))    insn = prev_nonnote_insn (insn);#endif  /* Get the pattern to emit and update our status.  */  if (save_p)    {      int i, j, k;      int ok;      /* See if we can save several registers with a single instruction.  	 Work backwards to the single register case.  */      for (i = MOVE_MAX / UNITS_PER_WORD; i > 0; i--)	{	  ok = 1;	  if (regno_save_mem[regno][i] != 0)	    for (j = 0; j < i; j++)	      {		if (! call_used_regs[regno + j] || call_fixed_regs[regno + j]		    || ! TEST_HARD_REG_BIT (hard_regs_live, regno + j)		    || TEST_HARD_REG_BIT (hard_regs_saved, regno + j))		  ok = 0;	      }	  else 	    continue;	  /* Must do this one save at a time */	  if (! ok)	    continue;          pat = gen_rtx (SET, VOIDmode, regno_save_mem[regno][i],		     gen_rtx (REG, GET_MODE (regno_save_mem[regno][i]), regno));          code = reg_save_code[regno][i];	  /* Set hard_regs_saved for all the registers we saved.  */	  for (k = 0; k < i; k++)	    {	      SET_HARD_REG_BIT (hard_regs_saved, regno + k);	      SET_HARD_REG_BIT (hard_regs_need_restore, regno + k);	      n_regs_saved++;	    }	  numregs = i;	  break;        }    }  else    {      int i, j, k;      int ok;      /* See if we can restore `maxrestore' registers at once.  Work	 backwards to the single register case.  */      for (i = maxrestore; i > 0; i--)	{	  ok = 1;	  if (regno_save_mem[regno][i])	    for (j = 0; j < i; j++)	      {	  	if (! TEST_HARD_REG_BIT (hard_regs_need_restore, regno + j))		  ok = 0;	      }	  else	    continue;	  /* Must do this one restore at a time */	  if (! ok)	    continue;	              pat = gen_rtx (SET, VOIDmode,		         gen_rtx (REG, GET_MODE (regno_save_mem[regno][i]), 				  regno), 			 regno_save_mem[regno][i]);          code = reg_restore_code[regno][i];	  /* Clear status for all registers we restored.  */	  for (k = 0; k < i; k++)	    {	      CLEAR_HARD_REG_BIT (hard_regs_need_restore, regno + k);	      n_regs_saved--;	    }	  numregs = i;	  break;        }    }  /* Emit the insn and set the code and mode.  */  insn = emit_insn_before (pat, insn);  PUT_MODE (insn, insn_mode);  INSN_CODE (insn) = code;  /* Tell our callers how many extra registers we saved/restored */  return numregs - 1;}

⌨️ 快捷键说明

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