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

📄 caller-save.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		  tempreg = 0;		else		  break;	      }	}      /* Push it on the stack.  */#ifdef STACK_GROWS_DOWNWARD      decrement = UNITS_PER_WORD;#else      decrement = - UNITS_PER_WORD;#endif      emit_insn_before (gen_add2_insn (stack_pointer_rtx,				       gen_rtx (CONST_INT, VOIDmode, -decrement)),			insn);      emit_insn_before (gen_move_insn (gen_rtx (MEM, Pmode, stack_pointer_rtx),				       tempreg),			insn);    }  /* Save the regs we are supposed to save, aside from TEMPREG.     Use TEMPREG for address calculations when needed.  */  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)    if (offset[regno] >= 0 && ! already_saved[regno]	&& tempreg != 0 && REGNO (tempreg) != regno)      {	rtx reg = save_reg_rtx[regno];	rtx addr1 = plus_constant (addr, offset[regno]);	rtx temp;	if (! memory_address_p (GET_MODE (reg), addr1))	  {	    if (GET_CODE (addr1) != PLUS)	      abort ();	    if (GET_CODE (XEXP (addr1, 1)) != CONST_INT		|| GET_CODE (XEXP (addr1, 0)) != REG)	      abort ();	    emit_insn_before (gen_move_insn (tempreg, XEXP (addr1, 0)), insn);	    emit_insn_before (gen_add2_insn (tempreg, XEXP (addr1, 1)), insn);	    addr1 = tempreg;	  }	temp = gen_rtx (MEM, GET_MODE (reg), addr1);	emit_insn_before (gen_move_insn (temp, reg), insn);	already_saved[regno] = 1;      }  /* If we pushed TEMPREG to make it free, pop it.  */  if (needpush)    {      emit_insn_before (gen_move_insn (tempreg,				       gen_rtx (MEM, Pmode, stack_pointer_rtx)),			insn);      emit_insn_before (gen_add2_insn (stack_pointer_rtx,				       gen_rtx (CONST_INT, VOIDmode, decrement)),			insn);    }  /* If TEMPREG itself needs saving, go back and save it.     There are plenty of free regs now, those already saved.  */  if (tempreg != 0      && offset[REGNO (tempreg)] >= 0 && ! already_saved[REGNO (tempreg)])    goto retry;}/* Emit a string of loads to restore the hard regs listed in   OFFSET[] from address ADDR; insert the loads after INSN.   OFFSET[reg] is -1 if reg should not be loaded, or a   suitably-aligned offset from ADDR.     The offsets actually used do not need to be those provided in   OFFSET, but should agree with whatever emit_mult_save does.  */static voidemit_mult_restore (insn, addr, offset)     rtx insn, addr;     int offset[];{  int regno;  /* Number of regs now needing to be restored.  */  int restore_count;  /* A register to use as a temporary for address calculations.  */  rtx tempreg;  /* A register available for that purpose but less desirable.  */  rtx maybe_tempreg;  /* A register that could be used as that temp if we push and pop it.  */  rtx can_push_reg;  /* Nonzero means we need to push and pop a register to use it as TEMPREG.  */  int needpush;  /* The amount the stack is decremented to save that register (if we do).  */  int decrement;  /* Record which regs we restore, in case we branch to retry.  */  char already_restored[FIRST_PSEUDO_REGISTER];  bzero (already_restored, sizeof already_restored);  /* Note: INSN can't be the last insn, since if it were,     no regs would live across it.  */  insn = NEXT_INSN (insn);  if (insn == 0)    abort ();  /* Now we can insert before INSN.     That is convenient because we can insert them in the order     that they should ultimately appear.  */  /* Hair is needed because sometimes the addresses to restore from are     not valid (offsets too big).     So we need a reg, TEMPREG, to compute addresses in.     We look first for an empty reg to use.     Sometimes no reg is empty.  Then we push a reg, use it, and pop it.     If all the suitable regs need to be restored,     that strategy won't work.  So we restore all but one, using that one     as a temporary.  Then we jump to `retry' to restore that one,     pushing and popping another (already restored) as a temporary.  */ retry:  needpush = 0;  tempreg = 0;  can_push_reg = 0;  restore_count = 0;  /* Set NEEDPUSH if any restore-addresses are not valid memory addresses.     If any register is available, record it in TEMPREG.     Otherwise, one register yet to be restored goes in MAYBE_TEMPREG,     and can be used as TEMPREG for any other regs to be restored.     If any register doesn't need restoring, record it in CAN_PUSH_REG.  */  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)    {      if (offset[regno] >= 0 && ! already_restored[regno])	{	  rtx reg = save_reg_rtx[regno];	  rtx addr1 = plus_constant (addr, offset[regno]);	  restore_count++;	  if (memory_address_p (GET_MODE (reg), addr1))	    needpush = 1;	  /* Find a call-clobbered reg that needs restoring.	     We can use it as a temporary if we defer restoring it.  */	  if (maybe_tempreg == 0)	    {	      maybe_tempreg = gen_rtx (REG, Pmode, regno);	      /* Don't use it if not valid for addressing.  */	      if (! strict_memory_address_p (QImode, maybe_tempreg))		maybe_tempreg = 0;	    }	}      /* If any call-clobbered reg is dead, put it in TEMPREG.	 It can be used as a temporary at no extra cost.  */      if (tempreg == 0 && call_used_regs[regno] && ! fixed_regs[regno]	  && offset[regno] < 0	  && HARD_REGNO_MODE_OK (regno, Pmode))	{	  tempreg = gen_rtx (REG, Pmode, regno);	  /* Don't use it if not valid for addressing.  */	  if (! strict_memory_address_p (QImode, tempreg))	    tempreg = 0;	}      /* Any non-call-clobbered reg, put in CAN_PUSH_REG.	 It can be used as a temporary if we push and pop it.  */      if (can_push_reg == 0 && ! call_used_regs[regno]	  && HARD_REGNO_MODE_OK (regno, Pmode))	{	  can_push_reg = gen_rtx (REG, Pmode, regno);	  /* Don't use it if not valid for addressing.  */	  if (! strict_memory_address_p (QImode, can_push_reg))	    can_push_reg = 0;	}      /* Any reg we already restored can be a temporary	 if we push and pop it.  */      if (can_push_reg == 0 && already_restored[regno]	  && HARD_REGNO_MODE_OK (regno, Pmode))	{	  can_push_reg = gen_rtx (REG, Pmode, regno);	  /* Don't use it if not valid for addressing.  */	  if (! strict_memory_address_p (QImode, can_push_reg))	    can_push_reg = 0;	}    }  /* If 2 or more regs need to be restored, use one as a temp reg     for the rest (if we need a tempreg).  */  if (tempreg == 0 && maybe_tempreg != 0 && restore_count > 1)    tempreg = maybe_tempreg;  /* Clear NEEDPUSH if we already found an empty reg.  */  if (tempreg != 0)    needpush = 0;  /* If we need a temp reg and none is free, make one free.  */  if (needpush)    {      tempreg = can_push_reg;      /* Push it on the stack.  */#ifdef STACK_GROWS_DOWNWARD      decrement = UNITS_PER_WORD;#else      decrement = - UNITS_PER_WORD;#endif      emit_insn_before (gen_add2_insn (stack_pointer_rtx,				       gen_rtx (CONST_INT, VOIDmode, -decrement)),			insn);      emit_insn_before (gen_move_insn (gen_rtx (MEM, Pmode, stack_pointer_rtx),				       tempreg),			insn);    }  /* Restore the regs we are supposed to restore, aside from TEMPREG.     Use TEMPREG for address calculations when needed.  */  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)    if (offset[regno] >= 0 && ! already_restored[regno]	&& tempreg != 0 && REGNO (tempreg) != regno)      {	rtx reg = save_reg_rtx[regno];	rtx addr1 = plus_constant (addr, offset[regno]);	rtx temp;	if (! memory_address_p (GET_MODE (reg), addr1))	  {	    if (GET_CODE (addr1) != PLUS)	      abort ();	    if (GET_CODE (XEXP (addr1, 1)) != CONST_INT		|| GET_CODE (XEXP (addr1, 0)) != REG)	      abort ();	    emit_insn_before (gen_move_insn (tempreg, XEXP (addr1, 0)), insn);	    emit_insn_before (gen_add2_insn (tempreg, XEXP (addr1, 1)), insn);	    addr1 = tempreg;	  }	temp = gen_rtx (MEM, GET_MODE (reg), addr1);	emit_insn_before (gen_move_insn (reg, temp), insn);	already_restored[regno] = 1;      }  /* If we pushed TEMPREG to make it free, pop it.  */  if (needpush)    {      emit_insn_before (gen_move_insn (tempreg,				       gen_rtx (MEM, Pmode, stack_pointer_rtx)),			insn);      emit_insn_before (gen_add2_insn (stack_pointer_rtx,				       gen_rtx (CONST_INT, VOIDmode, decrement)),			insn);    }  /* If TEMPREG itself needs restoring, go back and restore it.     We can find a reg already restored to push and use as a temporary.  */  if (tempreg != 0      && offset[REGNO (tempreg)] >= 0 && ! already_restored[REGNO (tempreg)])    goto retry;}/* Return the address of a new block of size SIZE on the stack.   The old save block is at ADDR; ADDR is 0 if no block exists yet.  */static rtxgrow_save_block (addr, size)     rtx addr;     int size;{  rtx newaddr;  /* Keep the size a multiple of the main allocation unit.  */  size = (((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1)	   / (BIGGEST_ALIGNMENT / BITS_PER_UNIT))	  * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));  /* If no save block exists yet, create one and return it.  */  if (! addr)    {      save_block_size = size;      return XEXP (assign_stack_local (BLKmode, size), 0);    }  /* Get a new block and coalesce it with the old one.  */  newaddr = XEXP (assign_stack_local (BLKmode, size - save_block_size), 0);  if (GET_CODE (newaddr) == PLUS      && XEXP (newaddr, 0) == frame_pointer_rtx      && GET_CODE (XEXP (newaddr, 1)) == CONST_INT      && GET_CODE (addr) == PLUS      && XEXP (addr, 0) == frame_pointer_rtx      && GET_CODE (XEXP (addr, 1)) == CONST_INT      && ((INTVAL (XEXP (newaddr, 1)) - INTVAL (XEXP (addr, 1))	   == size - save_block_size)	  || (INTVAL (XEXP (addr, 1)) - INTVAL (XEXP (newaddr, 1))	      == size - save_block_size)))    {      save_block_size = size;      if (INTVAL (XEXP (newaddr, 1)) < INTVAL (XEXP (addr, 1)))	return newaddr;      else	return addr;    }  /* They didn't coalesce, find out why */  abort ();			  save_block_size = size;  return XEXP (assign_stack_local (BLKmode, size), 0);}/* Return a machine mode that is legitimate for hard reg REGNO   and large enough to save the whole register.  */static enum machine_modechoose_hard_reg_mode (regno)     int regno;{  enum reg_class class = REGNO_REG_CLASS (regno);  if (CLASS_MAX_NREGS (class, DImode) == 1      && HARD_REGNO_MODE_OK (regno, DImode))    return DImode;  else if (CLASS_MAX_NREGS (class, DFmode) == 1	   && HARD_REGNO_MODE_OK (regno, DFmode))    return DFmode;  else if (CLASS_MAX_NREGS (class, SImode) == 1	   && HARD_REGNO_MODE_OK (regno, SImode))    return SImode;  else if (CLASS_MAX_NREGS (class, SFmode) == 1	   && HARD_REGNO_MODE_OK (regno, SFmode))    return SFmode;  else if (CLASS_MAX_NREGS (class, HImode) == 1	   && HARD_REGNO_MODE_OK (regno, HImode))    return HImode;  else    abort ();}

⌨️ 快捷键说明

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