Esempio n. 1
0
/* Called after register allocation to add any instructions needed for the
   epilogue.  Using an epilogue insn is favored compared to putting all of the
   instructions in output_function_epilogue(), since it allows the scheduler
   to intermix instructions with the restores of the caller saved registers.
   In some cases, it might be necessary to emit a barrier instruction as the
   first insn to prevent such scheduling.  */
void
fr30_expand_epilogue (void)
{
  int regno;

  /* Perform the inversion operations of the prologue.  */
  gcc_assert (current_frame_info.initialised);
  
  /* Pop local variables and arguments off the stack.
     If frame_pointer_needed is TRUE then the frame pointer register
     has actually been used as a frame pointer, and we can recover
     the stack pointer from it, otherwise we must unwind the stack
     manually.  */
  if (current_frame_info.frame_size > 0)
    {
      if (current_frame_info.save_fp && frame_pointer_needed)
	{
	  emit_insn (gen_leave_func ());
	  current_frame_info.save_fp = 0;
	}
      else if (current_frame_info.frame_size <= 508)
	emit_insn (gen_add_to_stack
		   (GEN_INT (current_frame_info.frame_size)));
      else
	{
	  rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
	  emit_insn (gen_movsi (tmp, GEN_INT (current_frame_info.frame_size)));
	  emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp));
	}
    }
  
  if (current_frame_info.save_fp)
    emit_insn (gen_movsi_pop (frame_pointer_rtx));
  
  /* Pop all the registers that were pushed.  */
  if (current_frame_info.save_rp)
    emit_insn (gen_movsi_pop (gen_rtx_REG (Pmode, RETURN_POINTER_REGNUM)));
    
  for (regno = 0; regno < STACK_POINTER_REGNUM; regno ++)
    if (current_frame_info.gmask & (1 << regno))
      emit_insn (gen_movsi_pop (gen_rtx_REG (Pmode, regno)));
  
  if (current_frame_info.pretend_size)
    emit_insn (gen_add_to_stack (GEN_INT (current_frame_info.pretend_size)));

  /* Reset state info for each function.  */
  current_frame_info = zero_frame_info;

  emit_jump_insn (gen_return_from_func ());
}
Esempio n. 2
0
void
moxie_expand_epilogue (void)
{
  int regno;
  rtx reg;

  if (cfun->machine->callee_saved_reg_size != 0)
    {
      reg = gen_rtx_REG (Pmode, MOXIE_R12);
      if (cfun->machine->callee_saved_reg_size <= 255)
	{
	  emit_move_insn (reg, hard_frame_pointer_rtx);
	  emit_insn (gen_subsi3 
		     (reg, reg, 
		      GEN_INT (cfun->machine->callee_saved_reg_size)));
	}
      else
	{
	  emit_move_insn (reg,
			  GEN_INT (-cfun->machine->callee_saved_reg_size));
	  emit_insn (gen_addsi3 (reg, reg, hard_frame_pointer_rtx));
	}
      for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0; )
	if (!fixed_regs[regno] && !call_used_regs[regno]
	    && df_regs_ever_live_p (regno))
	  {
	    rtx preg = gen_rtx_REG (Pmode, regno);
	    emit_insn (gen_movsi_pop (reg, preg));
	  }
    }

  emit_jump_insn (gen_returner ());
}
Esempio n. 3
0
rtx
fr30_move_double (rtx * operands)
{
  rtx src  = operands[1];
  rtx dest = operands[0];
  enum rtx_code src_code = GET_CODE (src);
  enum rtx_code dest_code = GET_CODE (dest);
  enum machine_mode mode = GET_MODE (dest);
  rtx val;

  start_sequence ();

  if (dest_code == REG)
    {
      if (src_code == REG)
	{
	  int reverse = (REGNO (dest) == REGNO (src) + 1);
	  
	  /* We normally copy the low-numbered register first.  However, if
	     the first register of operand 0 is the same as the second register
	     of operand 1, we must copy in the opposite order.  */
	  emit_insn (gen_rtx_SET (VOIDmode,
				  operand_subword (dest, reverse, TRUE, mode),
				  operand_subword (src,  reverse, TRUE, mode)));
	  
	  emit_insn (gen_rtx_SET (VOIDmode,
			      operand_subword (dest, !reverse, TRUE, mode),
			      operand_subword (src,  !reverse, TRUE, mode)));
	}
      else if (src_code == MEM)
	{
	  rtx addr = XEXP (src, 0);
	  int dregno = REGNO (dest);
	  rtx dest0;
	  rtx dest1;
	  rtx new_mem;
	  
	  /* If the high-address word is used in the address, we
	     must load it last.  Otherwise, load it first.  */
	  int reverse = (refers_to_regno_p (dregno, dregno + 1, addr, 0) != 0);

	  gcc_assert (GET_CODE (addr) == REG);
	  
	  dest0 = operand_subword (dest, reverse, TRUE, mode);
	  dest1 = operand_subword (dest, !reverse, TRUE, mode);

	  if (reverse)
	    {
	      emit_insn (gen_rtx_SET (VOIDmode, dest1,
				      adjust_address (src, SImode, 0)));
	      emit_insn (gen_rtx_SET (SImode, dest0,
				      gen_rtx_REG (SImode, REGNO (addr))));
	      emit_insn (gen_rtx_SET (SImode, dest0,
				      plus_constant (dest0, UNITS_PER_WORD)));

	      new_mem = gen_rtx_MEM (SImode, dest0);
	      MEM_COPY_ATTRIBUTES (new_mem, src);
	      
	      emit_insn (gen_rtx_SET (VOIDmode, dest0, new_mem));
	    }
	  else
	    {
	      emit_insn (gen_rtx_SET (VOIDmode, dest0,
				      adjust_address (src, SImode, 0)));
	      emit_insn (gen_rtx_SET (SImode, dest1,
				      gen_rtx_REG (SImode, REGNO (addr))));
	      emit_insn (gen_rtx_SET (SImode, dest1,
				      plus_constant (dest1, UNITS_PER_WORD)));

	      new_mem = gen_rtx_MEM (SImode, dest1);
	      MEM_COPY_ATTRIBUTES (new_mem, src);
	      
	      emit_insn (gen_rtx_SET (VOIDmode, dest1, new_mem));
	    }
	}
      else if (src_code == CONST_INT || src_code == CONST_DOUBLE)
	{
	  rtx words[2];
	  split_double (src, &words[0], &words[1]);
	  emit_insn (gen_rtx_SET (VOIDmode,
				  operand_subword (dest, 0, TRUE, mode),
				  words[0]));
      
	  emit_insn (gen_rtx_SET (VOIDmode,
				  operand_subword (dest, 1, TRUE, mode),
				  words[1]));
	}
    }
  else if (src_code == REG && dest_code == MEM)
    {
      rtx addr = XEXP (dest, 0);
      rtx src0;
      rtx src1;

      gcc_assert (GET_CODE (addr) == REG);
      
      src0 = operand_subword (src, 0, TRUE, mode);
      src1 = operand_subword (src, 1, TRUE, mode);
      
      emit_insn (gen_rtx_SET (VOIDmode, adjust_address (dest, SImode, 0),
			      src0));

      if (REGNO (addr) == STACK_POINTER_REGNUM
	  || REGNO (addr) == FRAME_POINTER_REGNUM)
	emit_insn (gen_rtx_SET (VOIDmode,
				adjust_address (dest, SImode, UNITS_PER_WORD),
				src1));
      else
	{
	  rtx new_mem;
	  
	  /* We need a scratch register to hold the value of 'address + 4'.
	     We ought to allow gcc to find one for us, but for now, just
	     push one of the source registers.  */
	  emit_insn (gen_movsi_push (src0));
	  emit_insn (gen_movsi_internal (src0, addr));
	  emit_insn (gen_addsi_small_int (src0, src0, GEN_INT (UNITS_PER_WORD)));
	  
	  new_mem = gen_rtx_MEM (SImode, src0);
	  MEM_COPY_ATTRIBUTES (new_mem, dest);
	  
	  emit_insn (gen_rtx_SET (VOIDmode, new_mem, src1));
	  emit_insn (gen_movsi_pop (src0));
	}
    }
  else
    /* This should have been prevented by the constraints on movdi_insn.  */
    gcc_unreachable ();
  
  val = get_insns ();
  end_sequence ();

  return val;
}