v850.c

来自「gcc3.2.1源代码」· C语言 代码 · 共 2,616 行 · 第 1/5 页

C
2,616
字号
  /* See if we have an insn that allocates stack space and saves the particular     registers we want to.  */  save_all = NULL_RTX;  if (TARGET_PROLOG_FUNCTION && num_save > 0 && actual_fsize >= default_stack)    {      int alloc_stack = (4 * num_save) + default_stack;      int unalloc_stack = actual_fsize - alloc_stack;      int save_func_len = 4;      int save_normal_len;      if (unalloc_stack)	save_func_len += CONST_OK_FOR_J (unalloc_stack) ? 2 : 4;      /* see if we would have used ep to save the stack */      if (TARGET_EP && num_save > 3 && (unsigned)actual_fsize < 255)	save_normal_len = (3 * 2) + (2 * num_save);      else	save_normal_len = 4 * num_save;      save_normal_len += CONST_OK_FOR_J (actual_fsize) ? 2 : 4;      /* Don't bother checking if we don't actually save any space.	 This happens for instance if one register is saved and additional	 stack space is allocated.  */      if (save_func_len < save_normal_len)	{	  save_all = gen_rtx_PARALLEL	    (VOIDmode,	     rtvec_alloc (num_save + (TARGET_V850 ? 2 : 1)));	  XVECEXP (save_all, 0, 0)	    = gen_rtx_SET (VOIDmode,			   stack_pointer_rtx,			   plus_constant (stack_pointer_rtx, -alloc_stack));	  if (TARGET_V850)	    {	      XVECEXP (save_all, 0, num_save+1)		= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 10));	    }	  offset = - default_stack;	  for (i = 0; i < num_save; i++)	    {	      XVECEXP (save_all, 0, i+1)		= gen_rtx_SET (VOIDmode,			       gen_rtx_MEM (Pmode,					    plus_constant (stack_pointer_rtx,							   offset)),			       save_regs[i]);	      offset -= 4;	    }	  code = recog (save_all, NULL_RTX, NULL);	  if (code >= 0)	    {	      rtx insn = emit_insn (save_all);	      INSN_CODE (insn) = code;	      actual_fsize -= alloc_stack;	      	      if (TARGET_DEBUG)		fprintf (stderr, "\Saved %d bytes via prologue function (%d vs. %d) for function %s\n",			 save_normal_len - save_func_len,			 save_normal_len, save_func_len,			 IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));	    }	  else	    save_all = NULL_RTX;	}    }  /* If no prolog save function is available, store the registers the old     fashioned way (one by one). */  if (!save_all)    {      /* Special case interrupt functions that save all registers for a call.  */      if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)	{	  emit_insn (gen_save_all_interrupt ());	}      else	{	  /* If the stack is too big, allocate it in chunks so we can do the	     register saves.  We use the register save size so we use the ep	     register.  */	  if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize))	    init_stack_alloc = compute_register_save_size (NULL);	  else	    init_stack_alloc = actual_fsize;	      	  /* Save registers at the beginning of the stack frame */	  offset = init_stack_alloc - 4;	  	  if (init_stack_alloc)	    emit_insn (gen_addsi3 (stack_pointer_rtx,				   stack_pointer_rtx,				   GEN_INT (-init_stack_alloc)));	  	  /* Save the return pointer first.  */	  if (num_save > 0 && REGNO (save_regs[num_save-1]) == LINK_POINTER_REGNUM)	    {	      emit_move_insn (gen_rtx_MEM (SImode,					   plus_constant (stack_pointer_rtx,							  offset)),			      save_regs[--num_save]);	      offset -= 4;	    }	  	  for (i = 0; i < num_save; i++)	    {	      emit_move_insn (gen_rtx_MEM (SImode,					   plus_constant (stack_pointer_rtx,							  offset)),			      save_regs[i]);	      offset -= 4;	    }	}    }  /* Allocate the rest of the stack that was not allocated above (either it is     > 32K or we just called a function to save the registers and needed more     stack.  */  if (actual_fsize > init_stack_alloc)    {      int diff = actual_fsize - init_stack_alloc;      if (CONST_OK_FOR_K (diff))	emit_insn (gen_addsi3 (stack_pointer_rtx,			       stack_pointer_rtx,			       GEN_INT (-diff)));      else	{	  rtx reg = gen_rtx_REG (Pmode, 12);	  emit_move_insn (reg, GEN_INT (-diff));	  emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));	}    }  /* If we need a frame pointer, set it up now.  */  if (frame_pointer_needed)    emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);}voidexpand_epilogue (){  unsigned int i;  int offset;  unsigned int size = get_frame_size ();  long reg_saved = 0;  unsigned int actual_fsize = compute_frame_size (size, &reg_saved);  unsigned int init_stack_free = 0;  rtx restore_regs[32];  rtx restore_all;  unsigned int num_restore;  unsigned int default_stack;  int code;  int interrupt_handler = v850_interrupt_function_p (current_function_decl);  /* Eliminate the initial stack stored by interrupt functions.  */  if (interrupt_handler)    {      actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;      if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)	actual_fsize -= INTERRUPT_ALL_SAVE_SIZE;    }  /* Cut off any dynamic stack created.  */  if (frame_pointer_needed)    emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);  /* Identify all of the saved registers.  */  num_restore = 0;  default_stack = 0;  for (i = 1; i < 31; i++)    {      if (((1L << i) & reg_saved) != 0)	restore_regs[num_restore++] = gen_rtx_REG (Pmode, i);    }  /* If the return pointer is saved, the helper functions also allocate     16 bytes of stack for arguments to be saved in.  */  if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)    {      restore_regs[num_restore++] = gen_rtx_REG (Pmode, LINK_POINTER_REGNUM);      default_stack = 16;    }  /* See if we have an insn that restores the particular registers we     want to.  */  restore_all = NULL_RTX;    if (TARGET_PROLOG_FUNCTION      && num_restore > 0      && actual_fsize >= default_stack      && !interrupt_handler)    {      int alloc_stack = (4 * num_restore) + default_stack;      int unalloc_stack = actual_fsize - alloc_stack;      int restore_func_len = 4;      int restore_normal_len;      if (unalloc_stack)	restore_func_len += CONST_OK_FOR_J (unalloc_stack) ? 2 : 4;      /* See if we would have used ep to restore the registers.  */      if (TARGET_EP && num_restore > 3 && (unsigned)actual_fsize < 255)	restore_normal_len = (3 * 2) + (2 * num_restore);      else	restore_normal_len = 4 * num_restore;      restore_normal_len += (CONST_OK_FOR_J (actual_fsize) ? 2 : 4) + 2;      /* Don't bother checking if we don't actually save any space.  */      if (restore_func_len < restore_normal_len)	{	  restore_all = gen_rtx_PARALLEL (VOIDmode,					  rtvec_alloc (num_restore + 2));	  XVECEXP (restore_all, 0, 0) = gen_rtx_RETURN (VOIDmode);	  XVECEXP (restore_all, 0, 1)	    = gen_rtx_SET (VOIDmode, stack_pointer_rtx,			    gen_rtx_PLUS (Pmode,					  stack_pointer_rtx,					  GEN_INT (alloc_stack)));	  offset = alloc_stack - 4;	  for (i = 0; i < num_restore; i++)	    {	      XVECEXP (restore_all, 0, i+2)		= gen_rtx_SET (VOIDmode,			       restore_regs[i],			       gen_rtx_MEM (Pmode,					    plus_constant (stack_pointer_rtx,							   offset)));	      offset -= 4;	    }	  code = recog (restore_all, NULL_RTX, NULL);	  	  if (code >= 0)	    {	      rtx insn;	      actual_fsize -= alloc_stack;	      if (actual_fsize)		{		  if (CONST_OK_FOR_K (actual_fsize))		    emit_insn (gen_addsi3 (stack_pointer_rtx,					   stack_pointer_rtx,					   GEN_INT (actual_fsize)));		  else		    {		      rtx reg = gen_rtx_REG (Pmode, 12);		      emit_move_insn (reg, GEN_INT (actual_fsize));		      emit_insn (gen_addsi3 (stack_pointer_rtx,					     stack_pointer_rtx,					     reg));		    }		}	      insn = emit_jump_insn (restore_all);	      INSN_CODE (insn) = code;	      if (TARGET_DEBUG)		fprintf (stderr, "\Saved %d bytes via epilogue function (%d vs. %d) in function %s\n",			 restore_normal_len - restore_func_len,			 restore_normal_len, restore_func_len,			 IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));	    }	  else	    restore_all = NULL_RTX;	}    }  /* If no epilog save function is available, restore the registers the     old fashioned way (one by one).  */  if (!restore_all)    {      /* If the stack is large, we need to cut it down in 2 pieces.  */      if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize))	init_stack_free = 4 * num_restore;      else	init_stack_free = actual_fsize;      /* Deallocate the rest of the stack if it is > 32K.  */      if (actual_fsize > init_stack_free)	{	  int diff;	  diff = actual_fsize - ((interrupt_handler) ? 0 : init_stack_free);	  if (CONST_OK_FOR_K (diff))	    emit_insn (gen_addsi3 (stack_pointer_rtx,				   stack_pointer_rtx,				   GEN_INT (diff)));	  else	    {	      rtx reg = gen_rtx_REG (Pmode, 12);	      emit_move_insn (reg, GEN_INT (diff));	      emit_insn (gen_addsi3 (stack_pointer_rtx,				     stack_pointer_rtx,				     reg));	    }	}      /* Special case interrupt functions that save all registers	 for a call.  */      if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)	{	  emit_insn (gen_restore_all_interrupt ());	}      else	{	  /* Restore registers from the beginning of the stack frame.  */	  offset = init_stack_free - 4;	  /* Restore the return pointer first.  */	  if (num_restore > 0	      && REGNO (restore_regs [num_restore - 1]) == LINK_POINTER_REGNUM)	    {	      emit_move_insn (restore_regs[--num_restore],			      gen_rtx_MEM (SImode,					   plus_constant (stack_pointer_rtx,							  offset)));	      offset -= 4;	    }	  for (i = 0; i < num_restore; i++)	    {	      emit_move_insn (restore_regs[i],			      gen_rtx_MEM (SImode,					   plus_constant (stack_pointer_rtx,							  offset)));	      emit_insn (gen_rtx_USE (VOIDmode, restore_regs[i]));	      offset -= 4;	    }	  /* Cut back the remainder of the stack.  */	  if (init_stack_free)	    emit_insn (gen_addsi3 (stack_pointer_rtx,				   stack_pointer_rtx,				   GEN_INT (init_stack_free)));	}      /* And return or use reti for interrupt handlers.  */      if (interrupt_handler)	emit_jump_insn (gen_restore_interrupt ());      else if (actual_fsize)	emit_jump_insn (gen_return_internal ());      else	emit_jump_insn (gen_return ());    }  current_function_anonymous_args = 0;  v850_interrupt_cache_p = FALSE;  v850_interrupt_p = FALSE;}/* Update the condition code from the insn.  */voidnotice_update_cc (body, insn)     rtx body;     rtx insn;{  switch (get_attr_cc (insn))    {    case CC_NONE:      /* Insn does not affect CC at all.  */      break;    case CC_NONE_0HIT:      /* Insn does not change CC, but the 0'th operand has been changed.  */      if (cc_status.value1 != 0	  && reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value1))	cc_status.value1 = 0;      break;    case CC_SET_ZN:      /* Insn sets the Z,N flags of CC to recog_data.operand[0].	 V,C is in an unusable state.  */      CC_STATUS_INIT;      cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY;      cc_status.value1 = recog_data.operand[0];      break;    case CC_SET_ZNV:      /* Insn sets the Z,N,V flags of CC to recog_data.operand[0].	 C is in an unusable state.  */      CC_STATUS_INIT;      cc_status.flags |= CC_NO_CARRY;      cc_status.value1 = recog_data.operand[0];      break;    case CC_COMPARE:      /* The insn is a compare instruction.  */      CC_STATUS_INIT;      cc_status.value1 = SET_SRC (body);      break;    case CC_CLOBBER:      /* Insn doesn't leave CC in a usable state.  */      CC_STATUS_INIT;      break;    }}/* Retrieve the data area that has been chosen for the given decl.  */v850_data_areav850_get_data_area (decl)     tree decl;{  if (lookup_attribute ("sda", DECL_ATTRIBUTES (decl)) != NULL_TREE)    return DATA_AREA_SDA;    if (lookup_attribute ("tda", DECL_ATTRIBUTES (decl)) != NULL_TREE)    return DATA_AREA_TDA;    if (lookup_attribute ("zda", DECL_ATTRIBUTES (decl)) != NULL_TREE)    return DATA_AREA_ZDA;  return DATA_AREA_NORMAL;}/* Store the indicated data area in the decl's attributes.  */static voidv850_set_data_area (decl, data_area)     tree decl;     v850_data_area data_area;{  tree name;    switch (data_area)    {    case DATA_AREA_SDA: name = get_identifier ("sda"); break;    case DATA_AREA_TDA: name = get_identifier ("tda"); break;    case DATA_AREA_ZDA: name = get_identifier ("zda"); break;    default:      return;    }  DECL_ATTRIBUTES (decl) = tree_cons    (name, NULL, DECL_ATTRIBUTES (decl));}const struct attribute_spec v850_attribute_table[] ={  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */  { "interrupt_handler", 0, 0, true,  false, false, v850_handle_interrupt_attribute },  { "interrupt",         0, 0, true,  false, false, v850_handle_interrupt_attribute },  { "sda",               0, 0, true,  false, false, v850_handle_data_area_attribute },  { "tda",               0, 0, true,  false, false, v850_handle_data_area_attribute },  { "zda",               0, 0, true,  false, false, v850_handle_data_area_attribute },  { NULL,                0, 0, false, false, false, NULL }};/* Handle an "interrupt" attribute; arguments as in   struct attribute_spec.handler.  */static treev850_handle_interrupt_attribute (node, name, args, flags, no_add_attrs)     tree *node;     tree name;     tree args ATTRIBUTE_UNUSED;     int flags ATTRIBUTE_UNUSED;     bool *no_add_attrs;{  if (TREE_CODE (*node) != FUNCTION_DECL)    {      warning ("`%s' attribute only applies to functions",	       IDENTIFIER_POINTER (name));      *no_add_attrs = true;    }  return NULL_TREE;}/* Handle a "sda", "tda" or "zda" attribute; arguments as in   struct attribute_spec.handler.  */static treev850_handle_data_area_attribute (node, name, args, flags, no_add_attrs)     tree *node;     tree name;     tree args ATTRIBUTE_UNUSED;     int flags ATTRIBUTE_UNUSED;     bool *no_add_attrs;{  v850_data_area data_area;  v850_data_area area;  tree decl = *node;  /* Implement data area attribute.  */  if (is_attribute_p ("sda", name))    data_area = DATA_AREA_SDA;  else if (is_attribute_p ("tda", name))    data_area = DATA_AREA_TDA;  else if (is_attribute_p ("zda", name))    data_area = DATA_AREA_ZDA;  else    abort ();    switch (TREE_CODE (decl))    {    case VAR_DECL:      if (current_function_decl != NULL_TREE)	{	  error_with_decl (decl, "\a data area attribute cannot be specified for local variables");	  *no_add_attrs = true;	}      /* Drop through.  */    case FUNCTION_DECL:      area = v850_get_data_area (decl);      if (area != DATA_AREA_NORMAL && data_area != area)	{	  error_with_decl (decl, "\data area of '%s' conflicts with previous declaration");

⌨️ 快捷键说明

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