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

📄 h8300.c

📁 Mac OS X 10.4.9 for x86 Source Code gcc 实现源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    default:      return NO_REGS;    }}/* Return the byte register name for a register rtx X.  B should be 0   if you want a lower byte register.  B should be 1 if you want an   upper byte register.  */static const char *byte_reg (rtx x, int b){  static const char *const names_small[] = {    "r0l", "r0h", "r1l", "r1h", "r2l", "r2h", "r3l", "r3h",    "r4l", "r4h", "r5l", "r5h", "r6l", "r6h", "r7l", "r7h"  };  if (!REG_P (x))    abort ();  return names_small[REGNO (x) * 2 + b];}/* REGNO must be saved/restored across calls if this macro is true.  */#define WORD_REG_USED(regno)						\  (regno < SP_REG							\   /* No need to save registers if this function will not return.  */	\   && ! TREE_THIS_VOLATILE (current_function_decl)			\   && (h8300_saveall_function_p (current_function_decl)			\       /* Save any call saved register that was used.  */		\       || (regs_ever_live[regno] && !call_used_regs[regno])		\       /* Save the frame pointer if it was used.  */			\       || (regno == HARD_FRAME_POINTER_REGNUM && regs_ever_live[regno])	\       /* Save any register used in an interrupt handler.  */		\       || (h8300_current_function_interrupt_function_p ()		\	   && regs_ever_live[regno])					\       /* Save call clobbered registers in non-leaf interrupt		\	  handlers.  */							\       || (h8300_current_function_interrupt_function_p ()		\	   && call_used_regs[regno]					\	   && !current_function_is_leaf)))/* Output assembly language to FILE for the operation OP with operand size   SIZE to adjust the stack pointer.  */static voidh8300_emit_stack_adjustment (int sign, unsigned int size){  /* If the frame size is 0, we don't have anything to do.  */  if (size == 0)    return;  /* H8/300 cannot add/subtract a large constant with a single     instruction.  If a temporary register is available, load the     constant to it and then do the addition.  */  if (TARGET_H8300      && size > 4      && !h8300_current_function_interrupt_function_p ()      && !(cfun->static_chain_decl != NULL && sign < 0))    {      rtx r3 = gen_rtx_REG (Pmode, 3);      emit_insn (gen_movhi (r3, GEN_INT (sign * size)));      emit_insn (gen_addhi3 (stack_pointer_rtx,			     stack_pointer_rtx, r3));    }  else    {      /* The stack adjustment made here is further optimized by the	 splitter.  In case of H8/300, the splitter always splits the	 addition emitted here to make the adjustment	 interrupt-safe.  */      if (Pmode == HImode)	emit_insn (gen_addhi3 (stack_pointer_rtx,			       stack_pointer_rtx, GEN_INT (sign * size)));      else	emit_insn (gen_addsi3 (stack_pointer_rtx,			       stack_pointer_rtx, GEN_INT (sign * size)));    }}/* Round up frame size SIZE.  */static intround_frame_size (int size){  return ((size + STACK_BOUNDARY / BITS_PER_UNIT - 1)	  & -STACK_BOUNDARY / BITS_PER_UNIT);}/* Compute which registers to push/pop.   Return a bit vector of registers.  */static unsigned intcompute_saved_regs (void){  unsigned int saved_regs = 0;  int regno;  /* Construct a bit vector of registers to be pushed/popped.  */  for (regno = 0; regno <= HARD_FRAME_POINTER_REGNUM; regno++)    {      if (WORD_REG_USED (regno))	saved_regs |= 1 << regno;    }  /* Don't push/pop the frame pointer as it is treated separately.  */  if (frame_pointer_needed)    saved_regs &= ~(1 << HARD_FRAME_POINTER_REGNUM);  return saved_regs;}/* Emit an insn to push register RN.  */static voidpush (int rn){  rtx reg = gen_rtx_REG (word_mode, rn);  rtx x;  if (TARGET_H8300)    x = gen_push_h8300 (reg);  else if (!TARGET_NORMAL_MODE)    x = gen_push_h8300hs_advanced (reg);  else    x = gen_push_h8300hs_normal (reg);  x = emit_insn (x);  REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_INC, stack_pointer_rtx, 0);}/* Emit an insn to pop register RN.  */static voidpop (int rn){  rtx reg = gen_rtx_REG (word_mode, rn);  rtx x;  if (TARGET_H8300)    x = gen_pop_h8300 (reg);  else if (!TARGET_NORMAL_MODE)    x = gen_pop_h8300hs_advanced (reg);  else    x = gen_pop_h8300hs_normal (reg);  x = emit_insn (x);  REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_INC, stack_pointer_rtx, 0);}/* Emit an instruction to push or pop NREGS consecutive registers   starting at register REGNO.  POP_P selects a pop rather than a   push and RETURN_P is true if the instruction should return.   It must be possible to do the requested operation in a single   instruction.  If NREGS == 1 && !RETURN_P, use a normal push   or pop insn.  Otherwise emit a parallel of the form:     (parallel       [(return)  ;; if RETURN_P	(save or restore REGNO)	(save or restore REGNO + 1)	...	(save or restore REGNO + NREGS - 1)	(set sp (plus sp (const_int adjust)))]  */static voidh8300_push_pop (int regno, int nregs, int pop_p, int return_p){  int i, j;  rtvec vec;  rtx sp, offset;  /* See whether we can use a simple push or pop.  */  if (!return_p && nregs == 1)    {      if (pop_p)	pop (regno);      else	push (regno);      return;    }  /* We need one element for the return insn, if present, one for each     register, and one for stack adjustment.  */  vec = rtvec_alloc ((return_p != 0) + nregs + 1);  sp = stack_pointer_rtx;  i = 0;  /* Add the return instruction.  */  if (return_p)    {      RTVEC_ELT (vec, i) = gen_rtx_RETURN (VOIDmode);      i++;    }  /* Add the register moves.  */  for (j = 0; j < nregs; j++)    {      rtx lhs, rhs;      if (pop_p)	{	  /* Register REGNO + NREGS - 1 is popped first.  Before the	     stack adjustment, its slot is at address @sp.  */	  lhs = gen_rtx_REG (SImode, regno + j);	  rhs = gen_rtx_MEM (SImode, plus_constant (sp, (nregs - j - 1) * 4));	}      else	{	  /* Register REGNO is pushed first and will be stored at @(-4,sp).  */	  lhs = gen_rtx_MEM (SImode, plus_constant (sp, (j + 1) * -4));	  rhs = gen_rtx_REG (SImode, regno + j);	}      RTVEC_ELT (vec, i + j) = gen_rtx_SET (VOIDmode, lhs, rhs);    }  /* Add the stack adjustment.  */  offset = GEN_INT ((pop_p ? nregs : -nregs) * 4);  RTVEC_ELT (vec, i + j) = gen_rtx_SET (VOIDmode, sp,					gen_rtx_PLUS (Pmode, sp, offset));  emit_insn (gen_rtx_PARALLEL (VOIDmode, vec));}/* Return true if X has the value sp + OFFSET.  */static inth8300_stack_offset_p (rtx x, int offset){  if (offset == 0)    return x == stack_pointer_rtx;  return (GET_CODE (x) == PLUS	  && XEXP (x, 0) == stack_pointer_rtx	  && GET_CODE (XEXP (x, 1)) == CONST_INT	  && INTVAL (XEXP (x, 1)) == offset);}/* A subroutine of h8300_ldm_stm_parallel.  X is one pattern in   something that may be an ldm or stm instruction.  If it fits   the required template, return the register it loads or stores,   otherwise return -1.   LOAD_P is true if X should be a load, false if it should be a store.   NREGS is the number of registers that the whole instruction is expected   to load or store.  INDEX is the index of the register that X should   load or store, relative to the lowest-numbered register.  */static inth8300_ldm_stm_regno (rtx x, int load_p, int index, int nregs){  int regindex, memindex, offset;  if (load_p)    regindex = 0, memindex = 1, offset = (nregs - index - 1) * 4;  else    memindex = 0, regindex = 1, offset = (index + 1) * -4;  if (GET_CODE (x) == SET      && GET_CODE (XEXP (x, regindex)) == REG      && GET_CODE (XEXP (x, memindex)) == MEM      && h8300_stack_offset_p (XEXP (XEXP (x, memindex), 0), offset))    return REGNO (XEXP (x, regindex));  return -1;}/* Return true if the elements of VEC starting at FIRST describe an   ldm or stm instruction (LOAD_P says which).  */static inth8300_ldm_stm_parallel (rtvec vec, int load_p, int first){  rtx last;  int nregs, i, regno, adjust;  /* There must be a stack adjustment, a register move, and at least one     other operation (a return or another register move).  */  if (GET_NUM_ELEM (vec) < 3)    return false;  /* Get the range of registers to be pushed or popped.  */  nregs = GET_NUM_ELEM (vec) - first - 1;  regno = h8300_ldm_stm_regno (RTVEC_ELT (vec, first), load_p, 0, nregs);  /* Check that the call to h8300_ldm_stm_regno succeeded and     that we're only dealing with GPRs.  */  if (regno < 0 || regno + nregs > 8)    return false;  /* 2-register h8s instructions must start with an even-numbered register.     3- and 4-register instructions must start with er0 or er4.  */  if (!TARGET_H8300SX)    {      if ((regno & 1) != 0)	return false;      if (nregs > 2 && (regno & 3) != 0)	return false;    }  /* Check the other loads or stores.  */  for (i = 1; i < nregs; i++)    if (h8300_ldm_stm_regno (RTVEC_ELT (vec, first + i), load_p, i, nregs)	!= regno + i)      return false;  /* Check the stack adjustment.  */  last = RTVEC_ELT (vec, first + nregs);  adjust = (load_p ? nregs : -nregs) * 4;  return (GET_CODE (last) == SET	  && SET_DEST (last) == stack_pointer_rtx	  && h8300_stack_offset_p (SET_SRC (last), adjust));}/* Return true if X is an ldm.l pattern.  X is known to be parallel.  */inth8300_ldm_parallel (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){  return h8300_ldm_stm_parallel (XVEC (x, 0), 1, 0);}/* Likewise stm.l.  */inth8300_stm_parallel (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){  return h8300_ldm_stm_parallel (XVEC (x, 0), 0, 0);}/* Likewise rts/l and rte/l.  Note that the .md pattern will check   for the return so there's no need to do that here.  */inth8300_return_parallel (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){  return h8300_ldm_stm_parallel (XVEC (x, 0), 1, 1);}/* This is what the stack looks like after the prolog of   a function with a frame has been set up:   <args>   PC   FP			<- fp   <locals>   <saved registers>	<- sp   This is what the stack looks like after the prolog of   a function which doesn't have a frame:   <args>   PC   <locals>   <saved registers>	<- sp*//* Generate RTL code for the function prologue.  */voidh8300_expand_prologue (void){  int regno;  int saved_regs;  int n_regs;  /* If the current function has the OS_Task attribute set, then     we have a naked prologue.  */  if (h8300_os_task_function_p (current_function_decl))    return;  if (h8300_monitor_function_p (current_function_decl))    /* My understanding of monitor functions is they act just like       interrupt functions, except the prologue must mask       interrupts.  */    emit_insn (gen_monitor_prologue ());  if (frame_pointer_needed)    {      /* Push fp.  */      push (HARD_FRAME_POINTER_REGNUM);      emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);    }  /* Push the rest of the registers in ascending order.  */  saved_regs = compute_saved_regs ();  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno += n_regs)    {      n_regs = 1;      if (saved_regs & (1 << regno))	{	  if (TARGET_H8300S)	    {	      /* See how many registers we can push at the same time.  */	      if ((!TARGET_H8300SX || (regno & 3) == 0)		  && ((saved_regs >> regno) & 0x0f) == 0x0f)		n_regs = 4;	      else if ((!TARGET_H8300SX || (regno & 3) == 0)		       && ((saved_regs >> regno) & 0x07) == 0x07)		n_regs = 3;	      else if ((!TARGET_H8300SX || (regno & 1) == 0)		       && ((saved_regs >> regno) & 0x03) == 0x03)		n_regs = 2;	    }	  h8300_push_pop (regno, n_regs, 0, 0);	}    }  /* Leave room for locals.  */  h8300_emit_stack_adjustment (-1, round_frame_size (get_frame_size ()));}/* Return nonzero if we can use "rts" for the function currently being   compiled.  */inth8300_can_use_return_insn_p (void){  return (reload_completed	  && !frame_pointer_needed	  && get_frame_size () == 0	  && compute_saved_regs () == 0);}/* Generate RTL code for the function epilogue.  */voidh8300_expand_epilogue (void){  int regno;  int saved_regs;  int n_regs;  HOST_WIDE_INT frame_size;  bool returned_p;  if (h8300_os_task_function_p (current_function_decl))    /* OS_Task epilogues are nearly naked -- they just have an       rts instruction.  */    return;  frame_size = round_frame_size (get_frame_size ());  returned_p = false;  /* Deallocate locals.  */  h8300_emit_stack_adjustment (1, frame_size);  /* Pop the saved registers in descending order.  */  saved_regs = compute_saved_regs ();  for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno -= n_regs)    {      n_regs = 1;      if (saved_regs & (1 << regno))	{	  if (TARGET_H8300S)	    {	      /* See how many registers we can pop at the same time.  */	      if ((TARGET_H8300SX || (regno & 3) == 3)		  && ((saved_regs << 3 >> regno) & 0x0f) == 0x0f)		n_regs = 4;	      else if ((TARGET_H8300SX || (regno & 3) == 2)		       && ((saved_regs << 2 >> regno) & 0x07) == 0x07)		n_regs = 3;	      else if ((TARGET_H8300SX || (regno & 1) == 1)		       && ((saved_regs << 1 >> regno) & 0x03) == 0x03)		n_regs = 2;	    }	  /* See if this pop would be the last insn before the return.	     If so, use rte/l or rts/l instead of pop or ldm.l.  */	  if (TARGET_H8300SX	      && !frame_pointer_needed	      && frame_size == 0	      && (saved_regs & ((1 << (regno - n_regs + 1)) - 1)) == 0)	    returned_p = true;	  h8300_push_pop (regno - n_regs + 1, n_regs, 1, returned_p);	}    }  /* Pop frame pointer if we had one.  */  if (frame_pointer_needed)    {      if (TARGET_H8300SX)	returned_p = true;      h8300_push_pop (HARD_FRAME_POINTER_REGNUM, 1, 1, returned_p);    }  if (!returned_p)

⌨️ 快捷键说明

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