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

📄 v850.c

📁 Mac OS X 10.4.9 for x86 Source Code gcc 实现源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	  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)        {          if (TARGET_V850E && ! TARGET_DISABLE_CALLT)            emit_insn (gen_callt_return_interrupt ());          else            emit_jump_insn (gen_return_interrupt ());	 }      else if (actual_fsize)	emit_jump_insn (gen_return_internal ());      else	emit_jump_insn (gen_return ());    }  v850_interrupt_cache_p = FALSE;  v850_interrupt_p = FALSE;}/* Update the condition code from the insn.  */voidnotice_update_cc (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 (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 (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 (tree * node,                                 tree name,                                 tree args ATTRIBUTE_UNUSED,                                 int flags ATTRIBUTE_UNUSED,                                 bool * no_add_attrs){  if (TREE_CODE (*node) != FUNCTION_DECL)    {      warning ("%qs 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 (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 ("%Jdata area attributes cannot be specified for "                 "local variables", decl, decl);	  *no_add_attrs = true;	}      /* Drop through.  */    case FUNCTION_DECL:      area = v850_get_data_area (decl);      if (area != DATA_AREA_NORMAL && data_area != area)	{	  error ("%Jdata area of '%D' conflicts with previous declaration",                 decl, decl);	  *no_add_attrs = true;	}      break;          default:      break;    }  return NULL_TREE;}/* Return nonzero if FUNC is an interrupt function as specified   by the "interrupt" attribute.  */intv850_interrupt_function_p (tree func){  tree a;  int ret = 0;  if (v850_interrupt_cache_p)    return v850_interrupt_p;  if (TREE_CODE (func) != FUNCTION_DECL)    return 0;  a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));  if (a != NULL_TREE)    ret = 1;  else    {      a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));      ret = a != NULL_TREE;    }  /* Its not safe to trust global variables until after function inlining has     been done.  */  if (reload_completed | reload_in_progress)    v850_interrupt_p = ret;  return ret;}static voidv850_encode_data_area (tree decl, rtx symbol){  int flags;  /* Map explicit sections into the appropriate attribute */  if (v850_get_data_area (decl) == DATA_AREA_NORMAL)    {      if (DECL_SECTION_NAME (decl))	{	  const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));	  	  if (streq (name, ".zdata") || streq (name, ".zbss"))	    v850_set_data_area (decl, DATA_AREA_ZDA);	  else if (streq (name, ".sdata") || streq (name, ".sbss"))	    v850_set_data_area (decl, DATA_AREA_SDA);	  else if (streq (name, ".tdata"))	    v850_set_data_area (decl, DATA_AREA_TDA);	}      /* If no attribute, support -m{zda,sda,tda}=n */      else	{	  int size = int_size_in_bytes (TREE_TYPE (decl));	  if (size <= 0)	    ;	  else if (size <= small_memory [(int) SMALL_MEMORY_TDA].max)	    v850_set_data_area (decl, DATA_AREA_TDA);	  else if (size <= small_memory [(int) SMALL_MEMORY_SDA].max)	    v850_set_data_area (decl, DATA_AREA_SDA);	  else if (size <= small_memory [(int) SMALL_MEMORY_ZDA].max)	    v850_set_data_area (decl, DATA_AREA_ZDA);	}            if (v850_get_data_area (decl) == DATA_AREA_NORMAL)	return;    }  flags = SYMBOL_REF_FLAGS (symbol);  switch (v850_get_data_area (decl))    {    case DATA_AREA_ZDA: flags |= SYMBOL_FLAG_ZDA; break;    case DATA_AREA_TDA: flags |= SYMBOL_FLAG_TDA; break;    case DATA_AREA_SDA: flags |= SYMBOL_FLAG_SDA; break;    default: abort ();    }  SYMBOL_REF_FLAGS (symbol) = flags;}static voidv850_encode_section_info (tree decl, rtx rtl, int first){  default_encode_section_info (decl, rtl, first);  if (TREE_CODE (decl) == VAR_DECL      && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))    v850_encode_data_area (decl, XEXP (rtl, 0));}/* Return true if the given RTX is a register which can be restored   by a function epilogue.  */intregister_is_ok_for_epilogue (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){  /* The save/restore routines can only cope with registers 20 - 31.  */  return ((GET_CODE (op) == REG)          && (((REGNO (op) >= 20) && REGNO (op) <= 31)));}/* Return nonzero if the given RTX is suitable for collapsing into   jump to a function epilogue.  */intpattern_is_ok_for_epilogue (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){  int count = XVECLEN (op, 0);  int i;    /* If there are no registers to restore then the function epilogue     is not suitable.  */  if (count <= 2)    return 0;  /* The pattern matching has already established that we are performing a     function epilogue and that we are popping at least one register.  We must     now check the remaining entries in the vector to make sure that they are     also register pops.  There is no good reason why there should ever be     anything else in this vector, but being paranoid always helps...     The test below performs the C equivalent of this machine description     pattern match:        (set (match_operand:SI n "register_is_ok_for_epilogue" "r")	  (mem:SI (plus:SI (reg:SI 3) (match_operand:SI n "immediate_operand" "i"))))     */  for (i = 3; i < count; i++)    {      rtx vector_element = XVECEXP (op, 0, i);      rtx dest;      rtx src;      rtx plus;            if (GET_CODE (vector_element) != SET)	return 0;            dest = SET_DEST (vector_element);      src = SET_SRC (vector_element);      if (GET_CODE (dest) != REG	  || GET_MODE (dest) != SImode	  || ! register_is_ok_for_epilogue (dest, SImode)	  || GET_CODE (src) != MEM	  || GET_MODE (src) != SImode)	return 0;      plus = XEXP (src, 0);      if (GET_CODE (plus) != PLUS	  || GET_CODE (XEXP (plus, 0)) != REG	  || GET_MODE (XEXP (plus, 0)) != SImode	  || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM	  || GET_CODE (XEXP (plus, 1)) != CONST_INT)	return 0;    }  return 1;}/* Construct a JR instruction to a routine that will perform the equivalent of   the RTL passed in as an argument.  This RTL is a function epilogue that   pops registers off the stack and possibly releases some extra stack space   as well.  The code has already verified that the RTL matches these   requirements.  */char *construct_restore_jr (rtx op){  int count = XVECLEN (op, 0);  int stack_bytes;  unsigned long int mask;  unsigned long int first;  unsigned long int last;  int i;  static char buff [100]; /* XXX */    if (count <= 2)    {      error ("bogus JR construction: %d\n", count);      return NULL;    }  /* Work out how many bytes to pop off the stack before retrieving     registers.  */  if (GET_CODE (XVECEXP (op, 0, 1)) != SET)    abort ();  if (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) != PLUS)    abort ();  if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) != CONST_INT)    abort ();      stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1));  /* Each pop will remove 4 bytes from the stack....  */  stack_bytes -= (count - 2) * 4;  /* Make sure that the amount we are popping either 0 or 16 bytes.  */  if (stack_bytes != 0 && stack_bytes != 16)    {      error ("bad amount of stack space removal: %d", stack_bytes);      return NULL;    }  /* Now compute the bit mask of registers to push.  */  mask = 0;  for (i = 2; i < count; i++)    {      rtx vector_element = XVECEXP (op, 0, i);            if (GET_CODE (vector_element) != SET)	abort ();      if (GET_CODE (SET_DEST (vector_element)) != REG)	abort ();      if (! register_is_ok_for_epilogue (SET_DEST (vector_element), SImode))	abort ();            mask |= 1 << REGNO (SET_DEST (vector_element));    }  /* Scan for the first register to pop.  */  for (first = 0; first < 32; first++)    {      if (mask & (1 << first))	break;    }  if (first >= 32)    abort ();  /* Discover the last register to pop.  */  if (mask & (1 << LINK_POINTER_REGNUM))    {      if (stack_bytes != 16)	abort ();            last = LINK_POINTER_REGNUM;    }  else    {      if (stack_bytes != 0)	abort ();            if ((mask & (1 << 29)) == 0)	abort ();            last = 29;    }  /* Note, it is possible to have gaps in the register mask.     We ignore this here, and generate a JR anyway.  We will     be popping more registers than is strictly necessary, but     it does save code space.  */    if (TARGET_LONG_CALLS)    {      char name[40];            if (first == last)	sprintf (name, "__return_%s", reg_names [first]);      else	sprintf (name, "__return_%s_%s", reg_names [first], reg_names [last]);            sprintf (buff, "movhi hi(%s), r0, r6\n\tmovea lo(%s), r6, r6\n\tjmp r6",	       name, name);    }  else    {      if (first == last)	sprintf (buff, "jr __return_%s", reg_names [first]);      else	sprintf (buff, "jr __return_%s_%s", reg_names [first], reg_names [last]);    }    return buff;}/* Return nonzero if the given RTX is suitable for collapsing into   a jump to a function prologue.  */intpattern_is_ok_for_prologue (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){  int count = XVECLEN (op, 0);  int i;   rtx vector_element;   /* If there are no registers to save then the function prologue     is not suitable.  */  if (count <= 2)    return 0;  /* T

⌨️ 快捷键说明

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