void
crx_expand_epilogue (void)
{
  rtx return_reg;

  /* Nonzero if we need to return and pop only RA. This will generate a
   * different insn. This differentiate is for the peepholes for call as last
   * statement in function. */
  int only_popret_RA = (save_regs[RETURN_ADDRESS_REGNUM]
			&& (sum_regs == UNITS_PER_WORD));

  /* Return register.  */
  return_reg = gen_rtx_REG (Pmode, RETURN_ADDRESS_REGNUM);

  if (frame_pointer_needed)
    /* Restore the stack pointer with the frame pointers value */
    emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);

  if (size_for_adjusting_sp > 0)
    emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
			   GEN_INT (size_for_adjusting_sp)));

  if (crx_interrupt_function_p ())
    emit_jump_insn (gen_interrupt_return ());
  else if (last_reg_to_save == -1)
    /* Nothing to pop */
    /* Don't output jump for interrupt routine, only retx.  */
    emit_jump_insn (gen_indirect_jump_return ());
  else if (only_popret_RA)
    emit_jump_insn (gen_popret_RA_return ());
  else
    emit_jump_insn (gen_pop_and_popret_return (GEN_INT (sum_regs)));
}
示例#2
0
文件: lm32.c 项目: boomeer/gcc
/* Create an emit instructions for a functions epilogue.  */
void
lm32_expand_epilogue (void)
{
  rtx ra_rtx = gen_rtx_REG (Pmode, RA_REGNUM);

  lm32_compute_frame_size (get_frame_size ());

  if (current_frame_info.total_size > 0)
    {
      /* Prevent stack code from being reordered.  */
      emit_insn (gen_blockage ());

      /* Restore callee save registers.  */
      if (current_frame_info.reg_save_mask != 0)
	expand_save_restore (&current_frame_info, 1);

      /* Deallocate stack.  */
      stack_adjust (current_frame_info.total_size);

      /* Return to calling function.  */
      emit_jump_insn (gen_return_internal (ra_rtx));
    }
  else
    {
      /* Return to calling function.  */
      emit_jump_insn (gen_return_internal (ra_rtx));
    }
}
示例#3
0
文件: moxie.c 项目: chinabin/gcc-tiny
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 ());
}
示例#4
0
文件: rtl-tests.c 项目: T-J-Teru/gcc
static void
test_uncond_jump ()
{
  rtx_insn *label = gen_label_rtx ();
  rtx jump_pat = gen_rtx_SET (pc_rtx,
			      gen_rtx_LABEL_REF (VOIDmode,
						 label));
  ASSERT_EQ (SET, jump_pat->code);
  ASSERT_EQ (LABEL_REF, SET_SRC (jump_pat)->code);
  ASSERT_EQ (label, label_ref_label (SET_SRC (jump_pat)));
  ASSERT_EQ (PC, SET_DEST (jump_pat)->code);

  verify_print_pattern ("pc=L0", jump_pat);

  ASSERT_RTL_DUMP_EQ ("(set (pc)\n"
		      "    (label_ref 0))",
		      jump_pat);

  rtx_insn *jump_insn = emit_jump_insn (jump_pat);
  ASSERT_FALSE (any_condjump_p (jump_insn));
  ASSERT_TRUE (any_uncondjump_p (jump_insn));
  ASSERT_TRUE (pc_set (jump_insn));
  ASSERT_TRUE (simplejump_p (jump_insn));
  ASSERT_TRUE (onlyjump_p (jump_insn));
  ASSERT_TRUE (control_flow_insn_p (jump_insn));

  ASSERT_RTL_DUMP_EQ ("(cjump_insn 1 (set (pc)\n"
		      "        (label_ref 0)))\n",
		      jump_insn);
}
示例#5
0
/* Generate code for transformation 2 (with MODE and OPERATION, operands OP1
   and OP2, result TARGET and probability of taking the optimal path PROB).  */
static rtx
gen_mod_pow2 (enum machine_mode mode, enum rtx_code operation, rtx target,
	      rtx op1, rtx op2, int prob)
{
  rtx tmp, tmp1, tmp2, tmp3, jump;
  rtx neq_label = gen_label_rtx ();
  rtx end_label = gen_label_rtx ();
  rtx sequence;

  start_sequence ();
  
  if (!REG_P (op2))
    {
      tmp = gen_reg_rtx (mode);
      emit_move_insn (tmp, copy_rtx (op2));
    }
  else
    tmp = op2;

  tmp1 = expand_simple_binop (mode, PLUS, tmp, constm1_rtx, NULL_RTX,
			      0, OPTAB_WIDEN);
  tmp2 = expand_simple_binop (mode, AND, tmp, tmp1, NULL_RTX,
			      0, OPTAB_WIDEN);
  do_compare_rtx_and_jump (tmp2, const0_rtx, NE, 0, mode, NULL_RTX,
			   NULL_RTX, neq_label);

  /* Add branch probability to jump we just created.  */
  jump = get_last_insn ();
  REG_NOTES (jump) = gen_rtx_EXPR_LIST (REG_BR_PROB,
					GEN_INT (REG_BR_PROB_BASE - prob),
					REG_NOTES (jump));

  tmp3 = expand_simple_binop (mode, AND, op1, tmp1, target,
			      0, OPTAB_WIDEN);
  if (tmp3 != target)
    emit_move_insn (copy_rtx (target), tmp3);
  emit_jump_insn (gen_jump (end_label));
  emit_barrier ();

  emit_label (neq_label);
  tmp1 = simplify_gen_binary (operation, mode, copy_rtx (op1), copy_rtx (tmp));
  tmp1 = force_operand (tmp1, target);
  if (tmp1 != target)
    emit_move_insn (target, tmp1);
  
  emit_label (end_label);

  sequence = get_insns ();
  end_sequence ();
  rebuild_jump_labels (sequence);
  return sequence;
}
示例#6
0
/* Generate code for transformation 1 (with MODE and OPERATION, operands OP1
   and OP2, whose value is expected to be VALUE, result TARGET and
   probability of taking the optimal path PROB).  */
static rtx
gen_divmod_fixed_value (enum machine_mode mode, enum rtx_code operation,
			rtx target, rtx op1, rtx op2, gcov_type value,
			int prob)
{
  rtx tmp, tmp1, jump;
  rtx neq_label = gen_label_rtx ();
  rtx end_label = gen_label_rtx ();
  rtx sequence;

  start_sequence ();
  
  if (!REG_P (op2))
    {
      tmp = gen_reg_rtx (mode);
      emit_move_insn (tmp, copy_rtx (op2));
    }
  else
    tmp = op2;

  do_compare_rtx_and_jump (tmp, GEN_INT (value), NE, 0, mode, NULL_RTX,
			   NULL_RTX, neq_label);

  /* Add branch probability to jump we just created.  */
  jump = get_last_insn ();
  REG_NOTES (jump) = gen_rtx_EXPR_LIST (REG_BR_PROB,
					GEN_INT (REG_BR_PROB_BASE - prob),
					REG_NOTES (jump));

  tmp1 = simplify_gen_binary (operation, mode,
			      copy_rtx (op1), GEN_INT (value));
  tmp1 = force_operand (tmp1, target);
  if (tmp1 != target)
    emit_move_insn (copy_rtx (target), copy_rtx (tmp1));

  emit_jump_insn (gen_jump (end_label));
  emit_barrier ();

  emit_label (neq_label);
  tmp1 = simplify_gen_binary (operation, mode,
			      copy_rtx (op1), copy_rtx (tmp));
  tmp1 = force_operand (tmp1, target);
  if (tmp1 != target)
    emit_move_insn (copy_rtx (target), copy_rtx (tmp1));
  
  emit_label (end_label);

  sequence = get_insns ();
  end_sequence ();
  rebuild_jump_labels (sequence);
  return sequence;
}
示例#7
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 ());
}
示例#8
0
static int
get_uncond_jump_length (void)
{
  rtx label, jump;
  int length;

  label = emit_label_before (gen_label_rtx (), get_insns ());
  jump = emit_jump_insn (gen_jump (label));

  length = get_attr_length (jump);

  delete_insn (jump);
  delete_insn (label);
  return length;
}
示例#9
0
文件: rtl-tests.c 项目: T-J-Teru/gcc
static void
test_single_set ()
{
  /* A label is not a SET.  */
  ASSERT_EQ (NULL_RTX, single_set (gen_label_rtx ()));

  /* An unconditional jump insn is a single SET.  */
  rtx set_pc = gen_rtx_SET (pc_rtx,
			    gen_rtx_LABEL_REF (VOIDmode,
					       gen_label_rtx ()));
  rtx_insn *jump_insn = emit_jump_insn (set_pc);
  ASSERT_EQ (set_pc, single_set (jump_insn));

  /* etc */
}
示例#10
0
rtx
compare_and_jump_seq (rtx op0, rtx op1, enum rtx_code comp, rtx label, int prob,
		      rtx cinsn)
{
  rtx seq, jump, cond;
  enum machine_mode mode;

  mode = GET_MODE (op0);
  if (mode == VOIDmode)
    mode = GET_MODE (op1);

  start_sequence ();
  if (GET_MODE_CLASS (mode) == MODE_CC)
    {
      /* A hack -- there seems to be no easy generic way how to make a
	 conditional jump from a ccmode comparison.  */
      gcc_assert (cinsn);
      cond = XEXP (SET_SRC (pc_set (cinsn)), 0);
      gcc_assert (GET_CODE (cond) == comp);
      gcc_assert (rtx_equal_p (op0, XEXP (cond, 0)));
      gcc_assert (rtx_equal_p (op1, XEXP (cond, 1)));
      emit_jump_insn (copy_insn (PATTERN (cinsn)));
      jump = get_last_insn ();
      gcc_assert (JUMP_P (jump));
      JUMP_LABEL (jump) = JUMP_LABEL (cinsn);
      LABEL_NUSES (JUMP_LABEL (jump))++;
      redirect_jump (jump, label, 0);
    }
  else
    {
      gcc_assert (!cinsn);

      op0 = force_operand (op0, NULL_RTX);
      op1 = force_operand (op1, NULL_RTX);
      do_compare_rtx_and_jump (op0, op1, comp, 0,
			       mode, NULL_RTX, NULL_RTX, label, -1);
      jump = get_last_insn ();
      gcc_assert (JUMP_P (jump));
      JUMP_LABEL (jump) = label;
      LABEL_NUSES (label)++;
    }
  add_reg_note (jump, REG_BR_PROB, GEN_INT (prob));

  seq = get_insns ();
  end_sequence ();

  return seq;
}
示例#11
0
文件: lm32.c 项目: boomeer/gcc
static void
gen_int_relational (enum rtx_code code,	
		    rtx result,	
		    rtx cmp0,	
		    rtx cmp1,	
		    rtx destination)	
{
  machine_mode mode;
  int branch_p;

  mode = GET_MODE (cmp0);
  if (mode == VOIDmode)
    mode = GET_MODE (cmp1);

  /* Is this a branch or compare.  */
  branch_p = (destination != 0);

  /* Instruction set doesn't support LE or LT, so swap operands and use 
     GE, GT.  */
  switch (code)
    {
    case LE:
    case LT:
    case LEU:
    case LTU:
      {
	rtx temp;

	code = swap_condition (code);
	temp = cmp0;
	cmp0 = cmp1;
	cmp1 = temp;
	break;
      }
    default:
      break;
    }

  if (branch_p)
    {
      rtx insn, cond, label;

      /* Operands must be in registers.  */
      if (!register_operand (cmp0, mode))
	cmp0 = force_reg (mode, cmp0);
      if (!register_operand (cmp1, mode))
	cmp1 = force_reg (mode, cmp1);

      /* Generate conditional branch instruction.  */
      cond = gen_rtx_fmt_ee (code, mode, cmp0, cmp1);
      label = gen_rtx_LABEL_REF (VOIDmode, destination);
      insn = gen_rtx_SET (pc_rtx, gen_rtx_IF_THEN_ELSE (VOIDmode,
							cond, label, pc_rtx));
      emit_jump_insn (insn);
    }
  else
    {
      /* We can't have const_ints in cmp0, other than 0.  */
      if ((GET_CODE (cmp0) == CONST_INT) && (INTVAL (cmp0) != 0))
	cmp0 = force_reg (mode, cmp0);

      /* If the comparison is against an int not in legal range
         move it into a register.  */
      if (GET_CODE (cmp1) == CONST_INT)
	{
	  switch (code)
	    {
	    case EQ:
	    case NE:
	    case LE:
	    case LT:
	    case GE:
	    case GT:
	      if (!satisfies_constraint_K (cmp1))
		cmp1 = force_reg (mode, cmp1);
	      break;
	    case LEU:
	    case LTU:
	    case GEU:
	    case GTU:
	      if (!satisfies_constraint_L (cmp1))
		cmp1 = force_reg (mode, cmp1);
	      break;
	    default:
	      gcc_unreachable ();
	    }
	}

      /* Generate compare instruction.  */
      emit_move_insn (result, gen_rtx_fmt_ee (code, mode, cmp0, cmp1));
    }
}
示例#12
0
void expand_epilogue (void)
{
    int i;
    int interrupt_func_p = cfun->machine->is_interrupt;
    int main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
    int wakeup_func_p = cfun->machine->is_wakeup;
    int cfp = cfun->machine->is_critical;
    int ree = cfun->machine->is_reenterant;
    int save_prologue_p = msp430_save_prologue_function_p (current_function_decl);
    /*int function_size;*/
    HOST_WIDE_INT size = get_frame_size();

    rtx insn;


    last_insn_address = 0;
    jump_tables_size = 0;
    epilogue_size = 0;
    /*function_size = (INSN_ADDRESSES (INSN_UID (get_last_insn ())) - INSN_ADDRESSES (INSN_UID (get_insns ())));*/

    if (cfun->machine->is_OS_task || cfun->machine->is_naked)
    {
        emit_jump_insn (gen_return ());	/* Otherwise, epilogue with 0 instruction causes a segmentation fault */
        return;
    }

    if (msp430_empty_epilogue ())
    {
        if (!return_issued)
        {
            /*fprintf (file, "\t%s\n", msp430_emit_return (NULL, NULL, NULL));*/
            emit_jump_insn (gen_return ());
            epilogue_size++;
        }
        /*fprintf (file, "\n\t/ * epilogue: not required * /\n");*/
        goto done_epilogue;
    }

    if ((cfp || interrupt_func_p) && ree)
        ree = 0;
    if (cfp && interrupt_func_p)
        cfp = 0;

    /*fprintf (file, "\n\t/ * epilogue : frame size = %d * /\n", size);*/

    if (main_p)
    {
        int totalsize = (size + 1) & ~1;
        if ((ACCUMULATE_OUTGOING_ARGS) && (!cfun->machine->is_leaf || cfun->calls_alloca) && crtl->outgoing_args_size)
            totalsize += crtl->outgoing_args_size;
        if (totalsize)
        {
            msp430_fh_add_sp_const(totalsize);
            /*fprintf (file, "\tadd\t#%d, r1\n", (size + 1) & ~1);*/
        }
        /*fprintf (file, "\tbr\t#%s\n", msp430_endup);*/
        msp430_fh_br_to_symbol_plus_offset(msp430_endup, 0);
        epilogue_size += 4;
        if (size == 1 || size == 2 || size == 4 || size == 8)
            epilogue_size--;
    }
    else
    {
        int totalsize = (size + 1) & ~1;
        if ((ACCUMULATE_OUTGOING_ARGS) && (!cfun->machine->is_leaf || cfun->calls_alloca) && crtl->outgoing_args_size)
            totalsize += crtl->outgoing_args_size;

        if (ree)
        {
            /*fprintf (file, "\teint\n");*/

            insn = emit_insn (gen_enable_interrupt());

            epilogue_size += 1;
        }

        if (totalsize)
        {
            /*fprintf (file, "\tadd\t#%d, r1\n", (size + 1) & ~1);*/
            msp430_fh_add_sp_const(totalsize);

            if (size == 1 || size == 2 || size == 4 || size == 8)
                epilogue_size += 1;
            else
                epilogue_size += 2;
        }

        if ((TARGET_SAVE_PROLOGUE || save_prologue_p)
                && !interrupt_func_p && msp430_func_num_saved_regs () > 2)
        {
            /*fprintf (file, "\tbr\t#__epilogue_restorer+%d\n",(8 - msp430_func_num_saved_regs ()) * 2);*/

            msp430_fh_br_to_symbol_plus_offset("__epilogue_restorer", (8 - msp430_func_num_saved_regs ()) * 2);

            epilogue_size += 2;
        }
        else if ((TARGET_SAVE_PROLOGUE || save_prologue_p) && interrupt_func_p)
        {
            /*fprintf (file, "\tbr\t#__epilogue_restorer_intr+%d\n", (12 - msp430_func_num_saved_regs ()) * 2);*/
            msp430_fh_br_to_symbol_plus_offset("__epilogue_restorer_intr", (12 - msp430_func_num_saved_regs ()) * 2);
        }
        else
        {
            for (i = 4; i < 16; i++)
            {
                if ((df_regs_ever_live_p(i)
                        && (!call_used_regs[i]
                            || interrupt_func_p))
                        || (!cfun->machine->is_leaf && (call_used_regs[i] && interrupt_func_p)))
                {
                    /*fprintf (file, "\tpop\tr%d\n", i);*/
                    msp430_fh_emit_pop_reg(i);
                    epilogue_size += 1;
                }
            }

            if (interrupt_func_p && wakeup_func_p)
            {
                /*fprintf (file, "\tbic\t#0xf0,0(r1)\n");*/
                msp430_fh_bic_deref_sp(0xF0);
                epilogue_size += 3;
            }
            emit_jump_insn (gen_return ());
            /*fprintf (file, "\tret\n");*/
            epilogue_size += 1;
        }
    }

    /*fprintf (file, "\t/ * epilogue end (size=%d) * /\n", epilogue_size);*/
done_epilogue:
    /*fprintf (file, "\t/ * function %s size %d (%d) * /\n", current_function_name, prologue_size + function_size + epilogue_size, function_size);*/

    msp430_commands_in_file += prologue_size + /*function_size +*/ epilogue_size;
    msp430_commands_in_prologues += prologue_size;
    msp430_commands_in_epilogues += epilogue_size;
}
示例#13
0
void
dcpu16_expand_epilogue(void)
{
  emit_jump_insn(gen_IITB_return());
}
示例#14
0
void
gen_int_relational (enum rtx_code code, /* relational test (EQ, etc) */
                    rtx result,		/* result to store comp. or 0 if branch */
                    rtx cmp0,		/* first operand to compare */
                    rtx cmp1,		/* second operand to compare */
                    rtx destination)	/* destination of the branch, or 0 if compare */
{
    enum machine_mode mode;
    int branch_p;

    mode = GET_MODE (cmp0);
    if (mode == VOIDmode)
        mode = GET_MODE (cmp1);

    /* Is this a branch or compare */
    branch_p = (destination != 0);

    /* Instruction set doesn't support LE or LT, so swap operands and use GE, GT */
    switch (code)
    {
    case LE:
    case LT:
    case LEU:
    case LTU:
        code = swap_condition (code);
        rtx temp = cmp0;
        cmp0 = cmp1;
        cmp1 = temp;
        break;
    default:
        break;
    }

    if (branch_p)
    {
        rtx insn;

        /* Operands must be in registers */
        if (!register_operand (cmp0, mode))
            cmp0 = force_reg (mode, cmp0);
        if (!register_operand (cmp1, mode))
            cmp1 = force_reg (mode, cmp1);

        /* Generate conditional branch instruction */
        rtx cond = gen_rtx_fmt_ee (code, mode, cmp0, cmp1);
        rtx label = gen_rtx_LABEL_REF (VOIDmode, destination);
        insn = gen_rtx_SET (VOIDmode, pc_rtx,
                            gen_rtx_IF_THEN_ELSE (VOIDmode,
                                    cond, label, pc_rtx));
        emit_jump_insn (insn);
    }
    else
    {
        /* We can't have const_ints in cmp0, other than 0 */
        if ((GET_CODE (cmp0) == CONST_INT) && (INTVAL (cmp0) != 0))
            cmp0 = force_reg (mode, cmp0);

        /* If the comparison is against an int not in legal range
           move it into a register */
        if (GET_CODE (cmp1) == CONST_INT)
        {
            HOST_WIDE_INT value = INTVAL (cmp1);
            switch (code)
            {
            case EQ:
            case NE:
            case LE:
            case LT:
            case GE:
            case GT:
                if (!MEDIUM_INT(value))
                    cmp1 = force_reg (mode, cmp1);
                break;
            case LEU:
            case LTU:
            case GEU:
            case GTU:
                if (!MEDIUM_UINT(value))
                    cmp1 = force_reg (mode, cmp1);
                break;
            default:
                abort ();
            }
        }

        /* Generate compare instruction */
        emit_move_insn (result, gen_rtx_fmt_ee (code, mode, cmp0, cmp1));
    }
}
示例#15
0
文件: spim0.1.c 项目: murukeshm/cs715
void
spim_epilogue()
{
	emit_jump_insn(gen_IITB_return());
}