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

📄 mn10300.c

📁 linux下的gcc编译器
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Generate an instruction that pushes several registers onto the stack.   Register K will be saved if bit K in MASK is set.  The function does   nothing if MASK is zero.   To be compatible with the "movm" instruction, the lowest-numbered   register must be stored in the lowest slot.  If MASK is the set   { R1,...,RN }, where R1...RN are ordered least first, the generated   instruction will have the form:       (parallel         (set (reg:SI 9) (plus:SI (reg:SI 9) (const_int -N*4)))	 (set (mem:SI (plus:SI (reg:SI 9)	                       (const_int -1*4)))	      (reg:SI RN))	 ...	 (set (mem:SI (plus:SI (reg:SI 9)	                       (const_int -N*4)))	      (reg:SI R1))) */voidmn10300_gen_multiple_store (mask)     int mask;{  if (mask != 0)    {      int i;      int count;      rtx par;      int pari;      /* Count how many registers need to be saved. */      count = 0;      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)	if ((mask & (1 << i)) != 0)	  count += 1;      /* We need one PARALLEL element to update the stack pointer and	 an additional element for each register that is stored. */      par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 1));      /* Create the instruction that updates the stack pointer. */      XVECEXP (par, 0, 0)	= gen_rtx_SET (SImode,		       stack_pointer_rtx,		       gen_rtx_PLUS (SImode,				     stack_pointer_rtx,				     GEN_INT (-count * 4)));      /* Create each store. */      pari = 1;      for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)	if ((mask & (1 << i)) != 0)	  {	    rtx address = gen_rtx_PLUS (SImode,					stack_pointer_rtx,					GEN_INT (-pari * 4));	    XVECEXP(par, 0, pari)	      = gen_rtx_SET (VOIDmode,			     gen_rtx_MEM (SImode, address),			     gen_rtx_REG (SImode, i));	    pari += 1;	  }      par = emit_insn (par);      RTX_FRAME_RELATED_P (par) = 1;    }}voidexpand_prologue (){  HOST_WIDE_INT size;  /* SIZE includes the fixed stack space needed for function calls.  */  size = get_frame_size () + current_function_outgoing_args_size;  size += (current_function_outgoing_args_size ? 4 : 0);  /* If we use any of the callee-saved registers, save them now. */  mn10300_gen_multiple_store (mn10300_get_live_callee_saved_regs ());  /* Now put the frame pointer into the frame pointer register.  */  if (frame_pointer_needed)    emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);  /* Allocate stack for this frame.  */  if (size)    emit_insn (gen_addsi3 (stack_pointer_rtx,			   stack_pointer_rtx,			   GEN_INT (-size)));}voidexpand_epilogue (){  HOST_WIDE_INT size;  /* SIZE includes the fixed stack space needed for function calls.  */  size = get_frame_size () + current_function_outgoing_args_size;  size += (current_function_outgoing_args_size ? 4 : 0);  /* Maybe cut back the stack, except for the register save area.     If the frame pointer exists, then use the frame pointer to     cut back the stack.     If the stack size + register save area is more than 255 bytes,     then the stack must be cut back here since the size + register     save size is too big for a ret/retf instruction.      Else leave it alone, it will be cut back as part of the     ret/retf instruction, or there wasn't any stack to begin with.     Under no circumstanes should the register save area be     deallocated here, that would leave a window where an interrupt     could occur and trash the register save area.  */  if (frame_pointer_needed)    {      emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);      size = 0;    }  else if (size + REG_SAVE_BYTES > 255)    {      emit_insn (gen_addsi3 (stack_pointer_rtx,			     stack_pointer_rtx,			     GEN_INT (size)));      size = 0;    }  /* Adjust the stack and restore callee-saved registers, if any.  */  if (size || regs_ever_live[2] || regs_ever_live[3]      || regs_ever_live[6] || regs_ever_live[7]      || regs_ever_live[14] || regs_ever_live[15]      || regs_ever_live[16] || regs_ever_live[17]      || frame_pointer_needed)    emit_jump_insn (gen_return_internal_regs		    (GEN_INT (size + REG_SAVE_BYTES)));  else    emit_jump_insn (gen_return_internal ());}/* 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 are unusable.  */      CC_STATUS_INIT;      cc_status.flags |= CC_NO_CARRY | CC_OVERFLOW_UNUSABLE;      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 unusable.  */      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_INVERT:      /* The insn is a compare instruction.  */      CC_STATUS_INIT;      cc_status.value1 = SET_SRC (body);      cc_status.flags |= CC_INVERTED;      break;    case CC_CLOBBER:      /* Insn doesn't leave CC in a usable state.  */      CC_STATUS_INIT;      break;    default:      abort ();    }}/* Recognize the PARALLEL rtx generated by mn10300_gen_multiple_store().   This function is for MATCH_PARALLEL and so assumes OP is known to be   parallel.  If OP is a multiple store, return a mask indicating which   registers it saves.  Return 0 otherwise.  */intstore_multiple_operation (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  int count;  int mask;  int i;  unsigned int last;  rtx elt;  count = XVECLEN (op, 0);  if (count < 2)    return 0;  /* Check that first instruction has the form (set (sp) (plus A B)) */  elt = XVECEXP (op, 0, 0);  if (GET_CODE (elt) != SET      || GET_CODE (SET_DEST (elt)) != REG      || REGNO (SET_DEST (elt)) != STACK_POINTER_REGNUM      || GET_CODE (SET_SRC (elt)) != PLUS)    return 0;  /* Check that A is the stack pointer and B is the expected stack size.     For OP to match, each subsequent instruction should push a word onto     the stack.  We therefore expect the first instruction to create     COUNT-1 stack slots. */  elt = SET_SRC (elt);  if (GET_CODE (XEXP (elt, 0)) != REG      || REGNO (XEXP (elt, 0)) != STACK_POINTER_REGNUM      || GET_CODE (XEXP (elt, 1)) != CONST_INT      || INTVAL (XEXP (elt, 1)) != -(count - 1) * 4)    return 0;  /* Now go through the rest of the vector elements.  They must be     ordered so that the first instruction stores the highest-numbered     register to the highest stack slot and that subsequent instructions     store a lower-numbered register to the slot below.     LAST keeps track of the smallest-numbered register stored so far.     MASK is the set of stored registers. */  last = FIRST_PSEUDO_REGISTER;  mask = 0;  for (i = 1; i < count; i++)    {      /* Check that element i is a (set (mem M) R) and that R is valid. */      elt = XVECEXP (op, 0, i);      if (GET_CODE (elt) != SET	  || GET_CODE (SET_DEST (elt)) != MEM	  || GET_CODE (SET_SRC (elt)) != REG	  || REGNO (SET_SRC (elt)) >= last)	return 0;      /* R was OK, so provisionally add it to MASK.  We return 0 in any	 case if the rest of the instruction has a flaw. */      last = REGNO (SET_SRC (elt));      mask |= (1 << last);      /* Check that M has the form (plus (sp) (const_int -I*4)) */      elt = XEXP (SET_DEST (elt), 0);      if (GET_CODE (elt) != PLUS	  || GET_CODE (XEXP (elt, 0)) != REG	  || REGNO (XEXP (elt, 0)) != STACK_POINTER_REGNUM	  || GET_CODE (XEXP (elt, 1)) != CONST_INT	  || INTVAL (XEXP (elt, 1)) != -i * 4)	return 0;    }  /* All or none of the callee-saved extended registers must be in the set. */  if ((mask & 0x3c000) != 0      && (mask & 0x3c000) != 0x3c000)    return 0;  return mask;}/* Return true if OP is a valid call operand.  */intcall_address_operand (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG);}/* What (if any) secondary registers are needed to move IN with mode   MODE into a register in register class CLASS.    We might be able to simplify this.  */enum reg_classsecondary_reload_class (class, mode, in)     enum reg_class class;     enum machine_mode mode;     rtx in;{  /* Memory loads less than a full word wide can't have an     address or stack pointer destination.  They must use     a data register as an intermediate register.  */  if ((GET_CODE (in) == MEM       || (GET_CODE (in) == REG	   && REGNO (in) >= FIRST_PSEUDO_REGISTER)       || (GET_CODE (in) == SUBREG	   && GET_CODE (SUBREG_REG (in)) == REG	   && REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER))      && (mode == QImode || mode == HImode)      && (class == ADDRESS_REGS || class == SP_REGS	  || class == SP_OR_ADDRESS_REGS))    {      if (TARGET_AM33)	return DATA_OR_EXTENDED_REGS;      return DATA_REGS;    }  /* We can't directly load sp + const_int into a data register;     we must use an address register as an intermediate.  */  if (class != SP_REGS      && class != ADDRESS_REGS      && class != SP_OR_ADDRESS_REGS      && class != SP_OR_EXTENDED_REGS      && class != ADDRESS_OR_EXTENDED_REGS      && class != SP_OR_ADDRESS_OR_EXTENDED_REGS      && (in == stack_pointer_rtx	  || (GET_CODE (in) == PLUS	      && (XEXP (in, 0) == stack_pointer_rtx		  || XEXP (in, 1) == stack_pointer_rtx))))    return ADDRESS_REGS;  if (GET_CODE (in) == PLUS      && (XEXP (in, 0) == stack_pointer_rtx	  || XEXP (in, 1) == stack_pointer_rtx))    {      if (TARGET_AM33)	return DATA_OR_EXTENDED_REGS;      return DATA_REGS;    }   /* Otherwise assume no secondary reloads are needed.  */  return NO_REGS;}intinitial_offset (from, to)     int from, to;{  /* The difference between the argument pointer and the frame pointer     is the size of the callee register save area.  */  if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)    {      if (regs_ever_live[2] || regs_ever_live[3]	  || regs_ever_live[6] || regs_ever_live[7]	  || regs_ever_live[14] || regs_ever_live[15]	  || regs_ever_live[16] || regs_ever_live[17]	  || frame_pointer_needed)	return REG_SAVE_BYTES;      else	return 0;    }  /* The difference between the argument pointer and the stack pointer is     the sum of the size of this function's frame, the callee register save     area, and the fixed stack space needed for function calls (if any).  */  if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)    {      if (regs_ever_live[2] || regs_ever_live[3]	  || regs_ever_live[6] || regs_ever_live[7]	  || regs_ever_live[14] || regs_ever_live[15]	  || regs_ever_live[16] || regs_ever_live[17]	  || frame_pointer_needed)	return (get_frame_size () + REG_SAVE_BYTES		+ (current_function_outgoing_args_size		   ? current_function_outgoing_args_size + 4 : 0));       else	return (get_frame_size ()		+ (current_function_outgoing_args_size		   ? current_function_outgoing_args_size + 4 : 0));     }  /* The difference between the frame pointer and stack pointer is the sum     of the size of this function's frame and the fixed stack space needed     for function calls (if any).  */  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)    return (get_frame_size ()	    + (current_function_outgoing_args_size	       ? current_function_outgoing_args_size + 4 : 0));   abort ();}/* Flush the argument registers to the stack for a stdarg function;   return the new argument pointer.  */rtxmn10300_builtin_saveregs (){  rtx offset, mem;  tree fntype = TREE_TYPE (current_function_decl);  int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0                   && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))                       != void_type_node)))                ? UNITS_PER_WORD : 0);  int set = get_varargs_alias_set ();  if (argadj)    offset = plus_constant (current_function_arg_offset_rtx, argadj);  else    offset = current_function_arg_offset_rtx;  mem = gen_rtx_MEM (SImode, current_function_internal_arg_pointer);  set_mem_alias_set (mem, set);  emit_move_insn (mem, gen_rtx_REG (SImode, 0));  mem = gen_rtx_MEM (SImode,		     plus_constant (current_function_internal_arg_pointer, 4));  set_mem_alias_set (mem, set);  emit_move_insn (mem, gen_rtx_REG (SImode, 1));  return copy_to_reg (expand_binop (Pmode, add_optab,				    current_function_internal_arg_pointer,				    offset, 0, 0, OPTAB_LIB_WIDEN));}voidmn10300_va_start (valist, nextarg)     tree valist;     rtx nextarg;{  nextarg = expand_builtin_saveregs ();  std_expand_builtin_va_start (valist, nextarg);}rtxmn10300_va_arg (valist, type)     tree valist, type;{  HOST_WIDE_INT align, rsize;  tree t, ptr, pptr;  /* Compute the rounded size of the type.  */  align = PARM_BOUNDARY / BITS_PER_UNIT;  rsize = (((int_size_in_bytes (type) + align - 1) / align) * align);  t = build (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist, 	     build_int_2 ((rsize > 8 ? 4 : rsize), 0));  TREE_SIDE_EFFECTS (t) = 1;  ptr = build_pointer_type (type);  /* "Large" types are passed by reference.  */  if (rsize > 8)    {      pptr = build_pointer_type (ptr);      t = build1 (NOP_EXPR, pptr, t);      TREE_SIDE_EFFECTS (t) = 1;

⌨️ 快捷键说明

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