Ejemplo n.º 1
0
Archivo: lm32.c Proyecto: boomeer/gcc
static void
stack_adjust (HOST_WIDE_INT amount)
{
  rtx insn;

  if (!IN_RANGE (amount, -32776, 32768))
    {
      /* r10 is caller saved so it can be used as a temp reg.  */
      rtx r10;
      r10 = gen_rtx_REG (word_mode, 10);
      insn = emit_move_insn (r10, GEN_INT (amount));
      if (amount < 0)
	RTX_FRAME_RELATED_P (insn) = 1;
      insn = emit_add (stack_pointer_rtx, stack_pointer_rtx, r10);
      if (amount < 0)
	RTX_FRAME_RELATED_P (insn) = 1;
    }
  else
    {
      insn = emit_add (stack_pointer_rtx,
		       stack_pointer_rtx, GEN_INT (amount));
      if (amount < 0)
	RTX_FRAME_RELATED_P (insn) = 1;
    }
}
Ejemplo n.º 2
0
Archivo: lm32.c Proyecto: boomeer/gcc
/* Generate and emit RTL to save or restore callee save registers.  */
static void
expand_save_restore (struct lm32_frame_info *info, int op)
{
  unsigned int reg_save_mask = info->reg_save_mask;
  int regno;
  HOST_WIDE_INT offset;
  rtx insn;

  /* Callee saves are below locals and above outgoing arguments.  */
  offset = info->args_size + info->callee_size;
  for (regno = 0; regno <= 31; regno++)
    {
      if ((reg_save_mask & (1 << regno)) != 0)
	{
	  rtx offset_rtx;
	  rtx mem;
	  
	  offset_rtx = GEN_INT (offset);
	  if (satisfies_constraint_K (offset_rtx))
	    {	
              mem = gen_rtx_MEM (word_mode,
                                 gen_rtx_PLUS (Pmode,
                                               stack_pointer_rtx,
                                               offset_rtx));
            }
          else
            {
              /* r10 is caller saved so it can be used as a temp reg.  */
              rtx r10;        
               
              r10 = gen_rtx_REG (word_mode, 10);
              insn = emit_move_insn (r10, offset_rtx);
              if (op == 0)
                RTX_FRAME_RELATED_P (insn) = 1;
              insn = emit_add (r10, r10, stack_pointer_rtx);
              if (op == 0)
                RTX_FRAME_RELATED_P (insn) = 1;                
              mem = gen_rtx_MEM (word_mode, r10);
            }                                                 	    
	    	    
	  if (op == 0)
	    insn = emit_move_insn (mem, gen_rtx_REG (word_mode, regno));
	  else
	    insn = emit_move_insn (gen_rtx_REG (word_mode, regno), mem);
        
	  /* only prologue instructions which set the sp fp or save a
	     register should be marked as frame related.  */
	  if (op == 0)
	    RTX_FRAME_RELATED_P (insn) = 1;
	  offset -= UNITS_PER_WORD;
	}
    }
}
Ejemplo n.º 3
0
void
moxie_expand_prologue (void)
{
  int regno;
  rtx insn;

  moxie_compute_frame ();

  if (flag_stack_usage_info)
    current_function_static_stack_size = cfun->machine->size_for_adjusting_sp;

  /* Save callee-saved registers.  */
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
    {
      if (!fixed_regs[regno] && df_regs_ever_live_p (regno) && !call_used_regs[regno])
	{
	  insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno)));
	  RTX_FRAME_RELATED_P (insn) = 1;
	}
    }

  if (cfun->machine->size_for_adjusting_sp > 0)
    {
      int i = cfun->machine->size_for_adjusting_sp; 
      while ((i >= 255) && (i <= 510))
	{
	  insn = emit_insn (gen_subsi3 (stack_pointer_rtx, 
					stack_pointer_rtx, 
					GEN_INT (255)));
	  RTX_FRAME_RELATED_P (insn) = 1;
	  i -= 255;
	}
      if (i <= 255)
	{
	  insn = emit_insn (gen_subsi3 (stack_pointer_rtx, 
					stack_pointer_rtx, 
					GEN_INT (i)));
	  RTX_FRAME_RELATED_P (insn) = 1;
	}
      else
	{
	  rtx reg = gen_rtx_REG (SImode, MOXIE_R12);
	  insn = emit_move_insn (reg, GEN_INT (i));
	  RTX_FRAME_RELATED_P (insn) = 1;
	  insn = emit_insn (gen_subsi3 (stack_pointer_rtx, 
					stack_pointer_rtx, 
					reg));
	  RTX_FRAME_RELATED_P (insn) = 1;
	}
    }
}
Ejemplo n.º 4
0
void
moxie_expand_prologue (void)
{
  int regno;
  rtx insn;

  moxie_compute_frame ();

  /* Save callee-saved registers.  */
  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
    {
      if (!fixed_regs[regno] && df_regs_ever_live_p (regno) && !call_used_regs[regno])
	{
	  insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno)));
	  RTX_FRAME_RELATED_P (insn) = 1;
	}
    }

  if (cfun->machine->size_for_adjusting_sp > 0)
    {
      if (cfun->machine->size_for_adjusting_sp <= 255)
	{
	  insn = emit_insn (gen_subsi3 (stack_pointer_rtx, 
					stack_pointer_rtx, 
					GEN_INT (cfun->machine->size_for_adjusting_sp)));
	  RTX_FRAME_RELATED_P (insn) = 1;
	}
      else
	{
	  insn = 
	    emit_insn (gen_movsi 
		       (gen_rtx_REG (Pmode, MOXIE_R5), 
			GEN_INT (-cfun->machine->size_for_adjusting_sp)));
	  RTX_FRAME_RELATED_P (insn) = 1;
	  insn = emit_insn (gen_addsi3 (stack_pointer_rtx, 
					stack_pointer_rtx, 
					gen_rtx_REG (Pmode, MOXIE_R5)));
	  RTX_FRAME_RELATED_P (insn) = 1;
	}	
    }
}
Ejemplo n.º 5
0
static void
adjust_frame_related_expr (rtx last_sp_set, rtx insn,
			   HOST_WIDE_INT this_adjust)
{
  rtx note = find_reg_note (last_sp_set, REG_FRAME_RELATED_EXPR, NULL_RTX);
  rtx new_expr = NULL_RTX;

  if (note == NULL_RTX && RTX_FRAME_RELATED_P (insn))
    return;

  if (note
      && GET_CODE (XEXP (note, 0)) == SEQUENCE
      && XVECLEN (XEXP (note, 0), 0) >= 2)
    {
      rtx expr = XEXP (note, 0);
      rtx last = XVECEXP (expr, 0, XVECLEN (expr, 0) - 1);
      int i;

      if (GET_CODE (last) == SET
	  && RTX_FRAME_RELATED_P (last) == RTX_FRAME_RELATED_P (insn)
	  && SET_DEST (last) == stack_pointer_rtx
	  && GET_CODE (SET_SRC (last)) == PLUS
	  && XEXP (SET_SRC (last), 0) == stack_pointer_rtx
	  && CONST_INT_P (XEXP (SET_SRC (last), 1)))
	{
	  XEXP (SET_SRC (last), 1)
	    = GEN_INT (INTVAL (XEXP (SET_SRC (last), 1)) + this_adjust);
	  return;
	}

      new_expr = gen_rtx_SEQUENCE (VOIDmode,
				   rtvec_alloc (XVECLEN (expr, 0) + 1));
      for (i = 0; i < XVECLEN (expr, 0); i++)
	XVECEXP (new_expr, 0, i) = XVECEXP (expr, 0, i);
    }
  else
    {
      new_expr = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (2));
      if (note)
	XVECEXP (new_expr, 0, 0) = XEXP (note, 0);
      else
	{
	  rtx expr = copy_rtx (single_set_for_csa (last_sp_set));

	  XEXP (SET_SRC (expr), 1)
	    = GEN_INT (INTVAL (XEXP (SET_SRC (expr), 1)) - this_adjust);
	  RTX_FRAME_RELATED_P (expr) = 1;
	  XVECEXP (new_expr, 0, 0) = expr;
	}
    }

  XVECEXP (new_expr, 0, XVECLEN (new_expr, 0) - 1)
    = copy_rtx (single_set_for_csa (insn));
  RTX_FRAME_RELATED_P (XVECEXP (new_expr, 0, XVECLEN (new_expr, 0) - 1))
    = RTX_FRAME_RELATED_P (insn);
  if (note)
    XEXP (note, 0) = new_expr;
  else
    add_reg_note (last_sp_set, REG_FRAME_RELATED_EXPR, new_expr);
}
Ejemplo n.º 6
0
Archivo: lm32.c Proyecto: boomeer/gcc
/* Create and emit instructions for a functions prologue.  */
void
lm32_expand_prologue (void)
{
  rtx insn;

  lm32_compute_frame_size (get_frame_size ());

  if (current_frame_info.total_size > 0)
    {
      /* Add space on stack new frame.  */
      stack_adjust (-current_frame_info.total_size);

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

      /* Setup frame pointer if it's needed.  */
      if (frame_pointer_needed == 1)
	{
	  /* Move sp to fp.  */
	  insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
	  RTX_FRAME_RELATED_P (insn) = 1; 

	  /* Add offset - Don't use total_size, as that includes pretend_size, 
             which isn't part of this frame?  */
	  insn = emit_add (frame_pointer_rtx, 
			   frame_pointer_rtx,
			   GEN_INT (current_frame_info.args_size +
				    current_frame_info.callee_size +
				    current_frame_info.locals_size));
	  RTX_FRAME_RELATED_P (insn) = 1;
	}

      /* Prevent prologue from being scheduled into function body.  */
      emit_insn (gen_blockage ());
    }
}
Ejemplo n.º 7
0
/* Generate and emit RTL to save or restore callee save registers */
static void
expand_save_restore (struct lm32_frame_info *info, int op)
{
    unsigned int reg_save_mask = info->reg_save_mask;
    int regno;
    HOST_WIDE_INT offset;
    rtx insn;

    /* Callee saves are below locals and above outgoing arguments */
    offset = info->args_size + info->callee_size;
    for (regno = 0; regno <= 31; regno++)
    {
        if ((reg_save_mask & (1 << regno)) != 0)
        {
            if (op == 0)
            {
                insn = emit_move_insn (gen_rtx_MEM (word_mode,
                                                    gen_rtx_PLUS (Pmode,
                                                            stack_pointer_rtx,
                                                            GEN_INT (offset))),
                                       gen_rtx_REG (word_mode, regno));
            }
            else
            {
                insn = emit_move_insn (gen_rtx_REG (word_mode, regno),
                                       gen_rtx_MEM (word_mode,
                                                    gen_rtx_PLUS (Pmode,
                                                            stack_pointer_rtx,
                                                            GEN_INT (offset))));
            }

            /* only prologue instructions which set the sp fp or save a
               register should be marked as frame related */
            if (op==0)
                RTX_FRAME_RELATED_P (insn) = 1;
            offset -= UNITS_PER_WORD;
        }
    }
}
Ejemplo n.º 8
0
void
fr30_expand_prologue (void)
{
  int regno;
  rtx insn;

  if (! current_frame_info.initialised)
    fr30_compute_frame_size (0, 0);

  /* This cases shouldn't happen.  Catch it now.  */
  gcc_assert (current_frame_info.total_size || !current_frame_info.gmask);

  /* Allocate space for register arguments if this is a variadic function.  */
  if (current_frame_info.pretend_size)
    {
      int regs_to_save = current_frame_info.pretend_size / UNITS_PER_WORD;
      
      /* Push argument registers into the pretend arg area.  */
      for (regno = FIRST_ARG_REGNUM + FR30_NUM_ARG_REGS; regno --, regs_to_save --;)
        {
	  insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno)));
	  RTX_FRAME_RELATED_P (insn) = 1;
	}
    }

  if (current_frame_info.gmask)
    {
      /* Save any needed call-saved regs.  */
      for (regno = STACK_POINTER_REGNUM; regno--;)
	{
	  if ((current_frame_info.gmask & (1 << regno)) != 0)
	    {
	      insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno)));
	      RTX_FRAME_RELATED_P (insn) = 1;
	    }
	}
    }

  /* Save return address if necessary.  */
  if (current_frame_info.save_rp)
    {
      insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, 
      						     RETURN_POINTER_REGNUM)));
      RTX_FRAME_RELATED_P (insn) = 1;
    }

  /* Save old frame pointer and create new one, if necessary.  */
  if (current_frame_info.save_fp)
    {
      if (current_frame_info.frame_size < ((1 << 10) - UNITS_PER_WORD))
        {
	  int enter_size = current_frame_info.frame_size + UNITS_PER_WORD;
	  rtx pattern;
	  
	  insn = emit_insn (gen_enter_func (GEN_INT (enter_size)));
          RTX_FRAME_RELATED_P (insn) = 1;
	  
	  pattern = PATTERN (insn);
	  
	  /* Also mark all 3 subexpressions as RTX_FRAME_RELATED_P. */
          if (GET_CODE (pattern) == PARALLEL)
            {
              int x;
              for (x = XVECLEN (pattern, 0); x--;)
		{
		  rtx part = XVECEXP (pattern, 0, x);
		  
		  /* One of the insns in the ENTER pattern updates the
		     frame pointer.  If we do not actually need the frame
		     pointer in this function then this is a side effect
		     rather than a desired effect, so we do not mark that
		     insn as being related to the frame set up.  Doing this
		     allows us to compile the crash66.C test file in the
		     G++ testsuite.  */
		  if (! frame_pointer_needed
		      && GET_CODE (part) == SET
		      && REGNO (SET_DEST (part)) == HARD_FRAME_POINTER_REGNUM)
		    RTX_FRAME_RELATED_P (part) = 0;
		  else
		    RTX_FRAME_RELATED_P (part) = 1;
		}
            }
	}
      else
	{
	  insn = emit_insn (gen_movsi_push (frame_pointer_rtx));
          RTX_FRAME_RELATED_P (insn) = 1;

	  if (frame_pointer_needed)
	    {
	      insn = emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
	      RTX_FRAME_RELATED_P (insn) = 1;
	    }
	}
    }

  /* Allocate the stack frame.  */
  if (current_frame_info.frame_size == 0)
    ; /* Nothing to do.  */
  else if (current_frame_info.save_fp
	   && current_frame_info.frame_size < ((1 << 10) - UNITS_PER_WORD))
    ; /* Nothing to do.  */
  else if (current_frame_info.frame_size <= 512)
    {
      insn = emit_insn (gen_add_to_stack (GEN_INT (- current_frame_info.frame_size)));
      RTX_FRAME_RELATED_P (insn) = 1;
    }
  else
    {
      rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
      insn = emit_insn (gen_movsi (tmp, GEN_INT (current_frame_info.frame_size)));
      RTX_FRAME_RELATED_P (insn) = 1;
      insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp));
      RTX_FRAME_RELATED_P (insn) = 1;
    }

  if (current_function_profile)
    emit_insn (gen_blockage ());
}
Ejemplo n.º 9
0
static void
combine_stack_adjustments_for_block (basic_block bb)
{
  HOST_WIDE_INT last_sp_adjust = 0;
  rtx last_sp_set = NULL_RTX;
  struct csa_reflist *reflist = NULL;
  rtx insn, next, set;
  struct record_stack_refs_data data;
  bool end_of_block = false;

  for (insn = BB_HEAD (bb); !end_of_block ; insn = next)
    {
      end_of_block = insn == BB_END (bb);
      next = NEXT_INSN (insn);

      if (! INSN_P (insn))
	continue;

      set = single_set_for_csa (insn);
      if (set)
	{
	  rtx dest = SET_DEST (set);
	  rtx src = SET_SRC (set);

	  /* Find constant additions to the stack pointer.  */
	  if (dest == stack_pointer_rtx
	      && GET_CODE (src) == PLUS
	      && XEXP (src, 0) == stack_pointer_rtx
	      && CONST_INT_P (XEXP (src, 1)))
	    {
	      HOST_WIDE_INT this_adjust = INTVAL (XEXP (src, 1));

	      /* If we've not seen an adjustment previously, record
		 it now and continue.  */
	      if (! last_sp_set)
		{
		  last_sp_set = insn;
		  last_sp_adjust = this_adjust;
		  continue;
		}

	      /* If not all recorded refs can be adjusted, or the
		 adjustment is now too large for a constant addition,
		 we cannot merge the two stack adjustments.

		 Also we need to be careful to not move stack pointer
		 such that we create stack accesses outside the allocated
		 area.  We can combine an allocation into the first insn,
		 or a deallocation into the second insn.  We can not
		 combine an allocation followed by a deallocation.

		 The only somewhat frequent occurrence of the later is when
		 a function allocates a stack frame but does not use it.
		 For this case, we would need to analyze rtl stream to be
		 sure that allocated area is really unused.  This means not
		 only checking the memory references, but also all registers
		 or global memory references possibly containing a stack
		 frame address.

		 Perhaps the best way to address this problem is to teach
		 gcc not to allocate stack for objects never used.  */

	      /* Combine an allocation into the first instruction.  */
	      if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0)
		{
		  if (try_apply_stack_adjustment (last_sp_set, reflist,
						  last_sp_adjust + this_adjust,
						  this_adjust))
		    {
		      if (RTX_FRAME_RELATED_P (last_sp_set))
			adjust_frame_related_expr (last_sp_set, insn,
						   this_adjust);
		      /* It worked!  */
		      delete_insn (insn);
		      last_sp_adjust += this_adjust;
		      continue;
		    }
		}

	      /* Otherwise we have a deallocation.  Do not combine with
		 a previous allocation.  Combine into the second insn.  */
	      else if (STACK_GROWS_DOWNWARD
		       ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
		{
		  if (try_apply_stack_adjustment (insn, reflist,
						  last_sp_adjust + this_adjust,
						  -last_sp_adjust))
		    {
		      /* It worked!  */
		      delete_insn (last_sp_set);
		      last_sp_set = insn;
		      last_sp_adjust += this_adjust;
		      free_csa_reflist (reflist);
		      reflist = NULL;
		      continue;
		    }
		}

	      /* Combination failed.  Restart processing from here.  If
		 deallocation+allocation conspired to cancel, we can
		 delete the old deallocation insn.  */
	      if (last_sp_set && last_sp_adjust == 0)
		delete_insn (last_sp_set);
	      free_csa_reflist (reflist);
	      reflist = NULL;
	      last_sp_set = insn;
	      last_sp_adjust = this_adjust;
	      continue;
	    }

	  /* Find a store with pre-(dec|inc)rement or pre-modify of exactly
	     the previous adjustment and turn it into a simple store.  This
	     is equivalent to anticipating the stack adjustment so this must
	     be an allocation.  */
	  if (MEM_P (dest)
	      && ((STACK_GROWS_DOWNWARD
		   ? (GET_CODE (XEXP (dest, 0)) == PRE_DEC
		      && last_sp_adjust
			 == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest)))
		   : (GET_CODE (XEXP (dest, 0)) == PRE_INC
		      && last_sp_adjust
		         == -(HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest))))
		  || ((STACK_GROWS_DOWNWARD
		       ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
		      && GET_CODE (XEXP (dest, 0)) == PRE_MODIFY
		      && GET_CODE (XEXP (XEXP (dest, 0), 1)) == PLUS
		      && XEXP (XEXP (XEXP (dest, 0), 1), 0)
			 == stack_pointer_rtx
		      && GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
		         == CONST_INT
		      && INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1))
		         == -last_sp_adjust))
	      && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
	      && !reg_mentioned_p (stack_pointer_rtx, src)
	      && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
	      && try_apply_stack_adjustment (insn, reflist, 0,
					     -last_sp_adjust))
	    {
	      delete_insn (last_sp_set);
	      free_csa_reflist (reflist);
	      reflist = NULL;
	      last_sp_set = NULL_RTX;
	      last_sp_adjust = 0;
	      continue;
	    }
	}

      data.insn = insn;
      data.reflist = reflist;
      if (!CALL_P (insn) && last_sp_set
	  && !for_each_rtx (&PATTERN (insn), record_stack_refs, &data))
	{
	   reflist = data.reflist;
	   continue;
	}
      reflist = data.reflist;

      /* Otherwise, we were not able to process the instruction.
	 Do not continue collecting data across such a one.  */
      if (last_sp_set
	  && (CALL_P (insn)
	      || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
	{
	  if (last_sp_set && last_sp_adjust == 0)
	    delete_insn (last_sp_set);
	  free_csa_reflist (reflist);
	  reflist = NULL;
	  last_sp_set = NULL_RTX;
	  last_sp_adjust = 0;
	}
    }

  if (last_sp_set && last_sp_adjust == 0)
    delete_insn (last_sp_set);

  if (reflist)
    free_csa_reflist (reflist);
}
Ejemplo n.º 10
0
void expand_prologue (void)
{
    int i;
    int main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
    int stack_reserve = 0;
    int offset;
    int save_prologue_p = msp430_save_prologue_function_p (current_function_decl);
    int num_saved_regs;
    HOST_WIDE_INT size = get_frame_size();

    rtx insn;	/* Last generated instruction */

    return_issued = 0;
    last_insn_address = 0;
    jump_tables_size = 0;
    prologue_size = 0;

    cfun->machine->is_naked = msp430_naked_function_p (current_function_decl);
    cfun->machine->is_interrupt = interrupt_function_p (current_function_decl);
    cfun->machine->is_OS_task = msp430_task_function_p (current_function_decl);

    cfun->machine->is_noint_hwmul = noint_hwmul_function_p (current_function_decl);
    cfun->machine->is_critical = msp430_critical_function_p(current_function_decl);
    cfun->machine->is_reenterant = msp430_reentrant_function_p(current_function_decl);
    cfun->machine->is_wakeup = wakeup_function_p (current_function_decl);
    cfun->machine->is_signal = signal_function_p (current_function_decl);


    /* check attributes compatibility */

    if ((cfun->machine->is_critical && cfun->machine->is_reenterant) || (cfun->machine->is_reenterant && cfun->machine->is_interrupt))
    {
        warning (OPT_Wattributes, "attribute 'reentrant' ignored");
        cfun->machine->is_reenterant = 0;
    }

    if (cfun->machine->is_critical && cfun->machine->is_interrupt)
    {
        warning (OPT_Wattributes, "attribute 'critical' ignored");
        cfun->machine->is_critical = 0;
    }

    if (cfun->machine->is_signal && !cfun->machine->is_interrupt)
    {
        warning (OPT_Wattributes, "attribute 'signal' has no meaning on MSP430 without 'interrupt' attribute.");
        cfun->machine->is_signal = 0;
    }

    /* naked function discards everything */
    if (cfun->machine->is_naked)
        return;

    stack_reserve = msp430_get_stack_reserve();
    offset = initial_elimination_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM) - 2;

    msp430_current_frame_offset = offset;

    if (cfun->machine->is_signal && cfun->machine->is_interrupt)
    {
        prologue_size += 1;

        insn = emit_insn (gen_enable_interrupt());
        /* fprintf (file, "\teint\t; enable nested interrupt\n"); */
    }

    if (main_p)
    {
        if (TARGET_NO_STACK_INIT)
        {
            if (size || stack_reserve)
            {
                /* fprintf (file, "\tsub\t#%d, r1\t", size + stack_reserve); */

                msp430_fh_sub_sp_const(size + stack_reserve);
            }

            if (frame_pointer_needed)
            {
                /* fprintf (file, "\tmov\tr1,r%d\n", FRAME_POINTER_REGNUM); */
                insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
                RTX_FRAME_RELATED_P (insn) = 1;

                prologue_size += 1;
            }

            if (size)
                prologue_size += 2;
            if (size == 1 || size == 2 || size == 4 || size == 8)
                prologue_size--;
        }
        else
        {
            /*fprintf (file, "\tmov\t#(%s-%d), r1\n", msp430_init_stack, size + stack_reserve);*/
            msp430_fh_load_sp_with_sym_plus_off(msp430_init_stack, -(size + stack_reserve));

            if (frame_pointer_needed)
            {
                /* fprintf (file, "\tmov\tr1,r%d\n", FRAME_POINTER_REGNUM); */

                insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
                RTX_FRAME_RELATED_P (insn) = 1;

                prologue_size += 1;
            }
            prologue_size += 2;
        }
        if ((ACCUMULATE_OUTGOING_ARGS) && (!cfun->machine->is_leaf || cfun->calls_alloca) && crtl->outgoing_args_size)
            msp430_fh_sub_sp_const(crtl->outgoing_args_size);
    }
    else	/* not a main() function */
    {
        /* Here, we've got a chance to jump to prologue saver */
        num_saved_regs = msp430_func_num_saved_regs ();

        if (!cfun->machine->is_interrupt && cfun->machine->is_critical)
        {
            prologue_size += 3;
            /*fprintf (file, "\tpush\tr2\n");
            fprintf (file, "\tdint\n");
            if (!size)
            	fprintf (file, "\tnop\n");*/

            insn = emit_insn (gen_push_sreg()); /* Pushing R2 using normal push creates a faulty INSN */
            RTX_FRAME_RELATED_P (insn) = 1;

            insn = emit_insn (gen_disable_interrupt());
            if (!size)
                insn = emit_insn (gen_nop());
        }

        if ((TARGET_SAVE_PROLOGUE || save_prologue_p)
                && !cfun->machine->is_interrupt && !arg_register_used[12] && num_saved_regs > 4)
        {
            /* TODO: Expand this as a separate INSN called "call prologue saver", having a meaning of pushing the registers and decreasing SP,
            	so that the debug info generation code will handle this correctly */

            /*fprintf (file, "\tsub\t#16, r1\n");
            fprintf (file, "\tmov\tr0, r12\n");
            fprintf (file, "\tadd\t#8, r12\n");
            fprintf (file, "\tbr\t#__prologue_saver+%d\n", (8 - num_saved_regs) * 4);*/

            msp430_fh_sub_sp_const(16);
            msp430_fh_gen_mov_pc_to_reg(12);
            msp430_fh_add_reg_const(12, 8);
            msp430_fh_br_to_symbol_plus_offset("__prologue_saver", (8 - num_saved_regs) * 4);

            if (cfun->machine->is_critical && 8 - num_saved_regs)
            {
                int n = 16 - num_saved_regs * 2;
                /*fprintf (file, "\tadd\t#%d, r1\n", n);*/
                msp430_fh_add_sp_const(n);
                if (n != 0 && n != 1 && n != 2 && n != 4 && n != 8)
                    prologue_size += 1;
            }
            else
                size -= 16 - num_saved_regs * 2;

            prologue_size += 7;
        }
        else if(!cfun->machine->is_OS_task)
        {
            for (i = 15; i >= 4; i--)
            {
                if ((df_regs_ever_live_p(i) && (!call_used_regs[i] || cfun->machine->is_interrupt)) ||
                        (!cfun->machine->is_leaf && (call_used_regs[i] && (cfun->machine->is_interrupt))))
                {
                    /*fprintf (file, "\tpush\tr%d\n", i);*/
                    msp430_fh_emit_push_reg(i);
                    prologue_size += 1;
                }
            }
        }

        if (size)
        {
            /* The next is a hack... I do not understand why, but if there
            ARG_POINTER_REGNUM and FRAME/STACK are different,
            the compiler fails to compute corresponding
            displacement */
            if (!optimize && !optimize_size
                    && df_regs_ever_live_p(ARG_POINTER_REGNUM))
            {
                int o = initial_elimination_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM) - size;

                /* fprintf (file, "\tmov\tr1, r%d\n", ARG_POINTER_REGNUM);
                fprintf (file, "\tadd\t#%d, r%d\n", o, ARG_POINTER_REGNUM); */

                insn = emit_move_insn (arg_pointer_rtx, stack_pointer_rtx);
                RTX_FRAME_RELATED_P (insn) = 1;
                msp430_fh_add_reg_const(ARG_POINTER_REGNUM, o);

                prologue_size += 2;
                if (o != 0 && o != 1 && o != 2 && o != 4 && o != 8)
                    prologue_size += 1;
            }

            /* adjust frame ptr... */
            if (size < 0)
            {
                int subtracted = (size + 1) & ~1;
                /*fprintf (file, "\tsub\t#%d, r1\t;	%d, fpn %d\n", subtracted, size, frame_pointer_needed);*/
                msp430_fh_sub_sp_const(subtracted);

            }
            else
            {
                int added;
                size = -size;
                added = (size + 1) & ~1;
                /*fprintf (file, "\tadd\t#%d, r1\t;    %d, fpn %d\n", (size + 1) & ~1, size, frame_pointer_needed);*/
                msp430_fh_add_sp_const(added);
            }

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

        if (frame_pointer_needed)
        {
            /*fprintf (file, "\tmov\tr1,r%d\n", FRAME_POINTER_REGNUM);*/

            insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
            RTX_FRAME_RELATED_P (insn) = 1;

            prologue_size += 1;
        }

        if ((ACCUMULATE_OUTGOING_ARGS) && (!cfun->machine->is_leaf || cfun->calls_alloca) && crtl->outgoing_args_size)
            msp430_fh_sub_sp_const(crtl->outgoing_args_size);

        /* disable interrupt for reentrant function */
        if (!cfun->machine->is_interrupt && cfun->machine->is_reenterant)
        {
            prologue_size += 1;
            /*fprintf (file, "\tdint\n");*/
            insn = emit_insn (gen_disable_interrupt());
        }
    }

    /*fprintf (file, "\t/ * prologue end (size=%d) * /\n\n", prologue_size);*/
}
Ejemplo n.º 11
0
static bool
deletable_insn_p (rtx_insn *insn, bool fast, bitmap arg_stores)
{
  rtx body, x;
  int i;
  df_ref def;

  if (CALL_P (insn)
      /* We cannot delete calls inside of the recursive dce because
	 this may cause basic blocks to be deleted and this messes up
	 the rest of the stack of optimization passes.  */
      && (!df_in_progress)
      /* We cannot delete pure or const sibling calls because it is
	 hard to see the result.  */
      && (!SIBLING_CALL_P (insn))
      /* We can delete dead const or pure calls as long as they do not
         infinite loop.  */
      && (RTL_CONST_OR_PURE_CALL_P (insn)
	  && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)))
    return find_call_stack_args (as_a <rtx_call_insn *> (insn), false,
				 fast, arg_stores);

  /* Don't delete jumps, notes and the like.  */
  if (!NONJUMP_INSN_P (insn))
    return false;

  /* Don't delete insns that may throw if we cannot do so.  */
  if (!(cfun->can_delete_dead_exceptions && can_alter_cfg)
      && !insn_nothrow_p (insn))
    return false;

  /* If INSN sets a global_reg, leave it untouched.  */
  FOR_EACH_INSN_DEF (def, insn)
    if (HARD_REGISTER_NUM_P (DF_REF_REGNO (def))
	&& global_regs[DF_REF_REGNO (def)])
      return false;
    /* Initialization of pseudo PIC register should never be removed.  */
    else if (DF_REF_REG (def) == pic_offset_table_rtx
	     && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
      return false;

  /* Callee-save restores are needed.  */
  if (RTX_FRAME_RELATED_P (insn)
      && crtl->shrink_wrapped_separate
      && find_reg_note (insn, REG_CFA_RESTORE, NULL))
    return false;

  body = PATTERN (insn);
  switch (GET_CODE (body))
    {
    case USE:
    case VAR_LOCATION:
      return false;

    case CLOBBER:
      if (fast)
	{
	  /* A CLOBBER of a dead pseudo register serves no purpose.
	     That is not necessarily true for hard registers until
	     after reload.  */
	  x = XEXP (body, 0);
	  return REG_P (x) && (!HARD_REGISTER_P (x) || reload_completed);
	}
      else
	/* Because of the way that use-def chains are built, it is not
	   possible to tell if the clobber is dead because it can
	   never be the target of a use-def chain.  */
	return false;

    case PARALLEL:
      for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
	if (!deletable_insn_p_1 (XVECEXP (body, 0, i)))
	  return false;
      return true;

    default:
      return deletable_insn_p_1 (body);
    }
}