stormy16.c

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

C
2,024
字号
     rtx x;     int strict;{  if (LEGITIMATE_ADDRESS_CONST_INT_P (x, 0))    return 1;  if (GET_CODE (x) == PLUS      && LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 0))    x = XEXP (x, 0);    if (GET_CODE (x) == POST_INC      || GET_CODE (x) == PRE_DEC)    x = XEXP (x, 0);    if (GET_CODE (x) == REG && REGNO_OK_FOR_BASE_P (REGNO (x))      && (! strict || REGNO (x) < FIRST_PSEUDO_REGISTER))    return 1;    return 0;}/* Return nonzero if memory address X (an RTX) can have different   meanings depending on the machine mode of the memory reference it   is used for or if the address is valid for some modes but not   others.   Autoincrement and autodecrement addresses typically have mode-dependent   effects because the amount of the increment or decrement is the size of the   operand being addressed.  Some machines have other mode-dependent addresses.   Many RISC machines have no mode-dependent addresses.   You may assume that ADDR is a valid address for the machine.        On this chip, this is true if the address is valid with an offset   of 0 but not of 6, because in that case it cannot be used as an   address for DImode or DFmode, or if the address is a post-increment   or pre-decrement address.  */intxstormy16_mode_dependent_address_p (x)     rtx x;{  if (LEGITIMATE_ADDRESS_CONST_INT_P (x, 0)      && ! LEGITIMATE_ADDRESS_CONST_INT_P (x, 6))    return 1;    if (GET_CODE (x) == PLUS      && LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 0)      && ! LEGITIMATE_ADDRESS_INTEGER_P (XEXP (x, 1), 6))    return 1;  if (GET_CODE (x) == PLUS)    x = XEXP (x, 0);  if (GET_CODE (x) == POST_INC      || GET_CODE (x) == PRE_DEC)    return 1;  return 0;}/* A C expression that defines the optional machine-dependent constraint   letters (`Q', `R', `S', `T', `U') that can be used to segregate specific   types of operands, usually memory references, for the target machine.   Normally this macro will not be defined.  If it is required for a particular   target machine, it should return 1 if VALUE corresponds to the operand type   represented by the constraint letter C.  If C is not defined as an extra   constraint, the value returned should be 0 regardless of VALUE.  */intxstormy16_extra_constraint_p (x, c)     rtx x;     int c;{  switch (c)    {      /* 'Q' is for pushes.  */    case 'Q':      return (GET_CODE (x) == MEM	      && GET_CODE (XEXP (x, 0)) == POST_INC	      && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx);      /* 'R' is for pops.  */    case 'R':      return (GET_CODE (x) == MEM	      && GET_CODE (XEXP (x, 0)) == PRE_DEC	      && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx);      /* 'S' is for immediate memory addresses.  */    case 'S':      return (GET_CODE (x) == MEM	      && GET_CODE (XEXP (x, 0)) == CONST_INT	      && xstormy16_legitimate_address_p (VOIDmode, XEXP (x, 0), 0));      /* 'T' is for Rx.  */    case 'T':      /* Not implemented yet.  */      return 0;      /* 'U' is for CONST_INT values not between 2 and 15 inclusive,	 for allocating a scratch register for 32-bit shifts.  */    case 'U':      return (GET_CODE (x) == CONST_INT	      && (INTVAL (x) < 2 || INTVAL (x) > 15));    default:      return 0;    }}intshort_memory_operand (x, mode)     rtx x;     enum machine_mode mode;{  if (! memory_operand (x, mode))    return 0;  return (GET_CODE (XEXP (x, 0)) != PLUS);}intnonimmediate_nonstack_operand (op, mode)     rtx op;     enum machine_mode mode;{  /* 'Q' is for pushes, 'R' for pops.  */  return (nonimmediate_operand (op, mode) 	  && ! xstormy16_extra_constraint_p (op, 'Q')	  && ! xstormy16_extra_constraint_p (op, 'R'));}/* Splitter for the 'move' patterns, for modes not directly implemeted   by hardware.  Emit insns to copy a value of mode MODE from SRC to   DEST.   This function is only called when reload_completed.   */void xstormy16_split_move (mode, dest, src)     enum machine_mode mode;     rtx dest;     rtx src;{  int num_words = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;  int direction, end, i;  int src_modifies = 0;  int dest_modifies = 0;  int src_volatile = 0;  int dest_volatile = 0;  rtx mem_operand;  rtx auto_inc_reg_rtx = NULL_RTX;    /* Check initial conditions.  */  if (! reload_completed      || mode == QImode || mode == HImode      || ! nonimmediate_operand (dest, mode)      || ! general_operand (src, mode))    abort ();  /* This case is not supported below, and shouldn't be generated.  */  if (GET_CODE (dest) == MEM      && GET_CODE (src) == MEM)    abort ();  /* This case is very very bad after reload, so trap it now.  */  if (GET_CODE (dest) == SUBREG      || GET_CODE (src) == SUBREG)    abort ();  /* The general idea is to copy by words, offsetting the source and     destination.  Normally the least-significant word will be copied     first, but for pre-dec operations it's better to copy the      most-significant word first.  Only one operand can be a pre-dec     or post-inc operand.       It's also possible that the copy overlaps so that the direction     must be reversed.  */  direction = 1;    if (GET_CODE (dest) == MEM)    {      mem_operand = XEXP (dest, 0);      dest_modifies = side_effects_p (mem_operand);      if (auto_inc_p (mem_operand))        auto_inc_reg_rtx = XEXP (mem_operand, 0);      dest_volatile = MEM_VOLATILE_P (dest);      if (dest_volatile)	{	  dest = copy_rtx (dest);	  MEM_VOLATILE_P (dest) = 0;	}    }  else if (GET_CODE (src) == MEM)    {      mem_operand = XEXP (src, 0);      src_modifies = side_effects_p (mem_operand);      if (auto_inc_p (mem_operand))        auto_inc_reg_rtx = XEXP (mem_operand, 0);      src_volatile = MEM_VOLATILE_P (src);      if (src_volatile)	{	  src = copy_rtx (src);	  MEM_VOLATILE_P (src) = 0;	}    }  else    mem_operand = NULL_RTX;  if (mem_operand == NULL_RTX)    {      if (GET_CODE (src) == REG	  && GET_CODE (dest) == REG	  && reg_overlap_mentioned_p (dest, src)	  && REGNO (dest) > REGNO (src))	direction = -1;    }  else if (GET_CODE (mem_operand) == PRE_DEC      || (GET_CODE (mem_operand) == PLUS 	  && GET_CODE (XEXP (mem_operand, 0)) == PRE_DEC))    direction = -1;  else if (GET_CODE (src) == MEM	   && reg_overlap_mentioned_p (dest, src))    {      int regno;      if (GET_CODE (dest) != REG)	abort ();      regno = REGNO (dest);            if (! refers_to_regno_p (regno, regno + num_words, mem_operand, 0))	abort ();            if (refers_to_regno_p (regno, regno + 1, mem_operand, 0))	direction = -1;      else if (refers_to_regno_p (regno + num_words - 1, regno + num_words,				  mem_operand, 0))	direction = 1;      else	/* This means something like	   (set (reg:DI r0) (mem:DI (reg:HI r1)))	   which we'd need to support by doing the set of the second word	   last.  */	abort ();    }  end = direction < 0 ? -1 : num_words;  for (i = direction < 0 ? num_words - 1 : 0; i != end; i += direction)    {      rtx w_src, w_dest, insn;      if (src_modifies)	w_src = gen_rtx_MEM (word_mode, mem_operand);      else	w_src = simplify_gen_subreg (word_mode, src, mode, i * UNITS_PER_WORD);      if (src_volatile)	MEM_VOLATILE_P (w_src) = 1;      if (dest_modifies)	w_dest = gen_rtx_MEM (word_mode, mem_operand);      else	w_dest = simplify_gen_subreg (word_mode, dest, mode, 				      i * UNITS_PER_WORD);      if (dest_volatile)	MEM_VOLATILE_P (w_dest) = 1;            /* The simplify_subreg calls must always be able to simplify.  */      if (GET_CODE (w_src) == SUBREG	  || GET_CODE (w_dest) == SUBREG)	abort ();            insn = emit_insn (gen_rtx_SET (VOIDmode, w_dest, w_src));      if (auto_inc_reg_rtx)        REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC,                                            auto_inc_reg_rtx,					    REG_NOTES (insn));    }}/* Expander for the 'move' patterns.  Emit insns to copy a value of   mode MODE from SRC to DEST.  */void xstormy16_expand_move (mode, dest, src)     enum machine_mode mode;     rtx dest;     rtx src;{  /* There are only limited immediate-to-memory move instructions.  */  if (! reload_in_progress      && ! reload_completed      && GET_CODE (dest) == MEM      && (GET_CODE (XEXP (dest, 0)) != CONST_INT	  || ! xstormy16_legitimate_address_p (mode, XEXP (dest, 0), 0))      && GET_CODE (src) != REG      && GET_CODE (src) != SUBREG)    src = copy_to_mode_reg (mode, src);  /* Don't emit something we would immediately split.  */  if (reload_completed      && mode != HImode && mode != QImode)    {      xstormy16_split_move (mode, dest, src);      return;    }    emit_insn (gen_rtx_SET (VOIDmode, dest, src));}/* Stack Layout:   The stack is laid out as follows:SP->FP->	Local variables	Register save area (up to 4 words)	Argument register save area for stdarg (NUM_ARGUMENT_REGISTERS words)AP->	Return address (two words)	9th procedure parameter word	10th procedure parameter word	...	last procedure parameter word  The frame pointer location is tuned to make it most likely that all  parameters and local variables can be accessed using a load-indexed  instruction.  *//* A structure to describe the layout.  */struct xstormy16_stack_layout{  /* Size of the topmost three items on the stack.  */  int locals_size;  int register_save_size;  int stdarg_save_size;  /* Sum of the above items.  */  int frame_size;  /* Various offsets.  */  int first_local_minus_ap;  int sp_minus_fp;  int fp_minus_ap;};/* Does REGNO need to be saved?  */#define REG_NEEDS_SAVE(REGNUM, IFUN)					\  ((regs_ever_live[REGNUM] && ! call_used_regs[REGNUM])			\   || (IFUN && ! fixed_regs[REGNUM] && call_used_regs[REGNUM]		\       && (regs_ever_live[REGNUM] || ! current_function_is_leaf)))/* Compute the stack layout.  */struct xstormy16_stack_layout xstormy16_compute_stack_layout (){  struct xstormy16_stack_layout layout;  int regno;  const int ifun = xstormy16_interrupt_function_p ();  layout.locals_size = get_frame_size ();    layout.register_save_size = 0;  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)    if (REG_NEEDS_SAVE (regno, ifun))      layout.register_save_size += UNITS_PER_WORD;    if (current_function_varargs || current_function_stdarg)    layout.stdarg_save_size = NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD;  else    layout.stdarg_save_size = 0;    layout.frame_size = (layout.locals_size 		       + layout.register_save_size 		       + layout.stdarg_save_size);    if (current_function_args_size <= 2048 && current_function_args_size != -1)    {      if (layout.frame_size + INCOMING_FRAME_SP_OFFSET 	  + current_function_args_size <= 2048)	layout.fp_minus_ap = layout.frame_size + INCOMING_FRAME_SP_OFFSET;      else	layout.fp_minus_ap = 2048 - current_function_args_size;    }  else    layout.fp_minus_ap = (layout.stdarg_save_size 			  + layout.register_save_size			  + INCOMING_FRAME_SP_OFFSET);  layout.sp_minus_fp = (layout.frame_size + INCOMING_FRAME_SP_OFFSET 			- layout.fp_minus_ap);  layout.first_local_minus_ap = layout.sp_minus_fp - layout.locals_size;  return layout;}/* Determine how all the special registers get eliminated.  */intxstormy16_initial_elimination_offset (from, to)     int from, to;{  struct xstormy16_stack_layout layout;  int result;    layout = xstormy16_compute_stack_layout ();  if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)    result = layout.sp_minus_fp - layout.locals_size;  else if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)    result = -layout.locals_size;  else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)    result = -layout.fp_minus_ap;  else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)    result = -(layout.sp_minus_fp + layout.fp_minus_ap);  else    abort ();  return result;}static rtxemit_addhi3_postreload (dest, src0, src1)     rtx dest;     rtx src0;     rtx src1;{  rtx set, clobber, insn;    set = gen_rtx_SET (VOIDmode, dest, gen_rtx_PLUS (HImode, src0, src1));  clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (BImode, 16));  insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber)));  return insn;}/* Called after register allocation to add any instructions needed for   the prologue.  Using a prologue insn is favored compared to putting   all of the instructions in the TARGET_ASM_FUNCTION_PROLOGUE macro,   since it allows the scheduler to intermix instructions with the   saves of the caller saved registers.  In some cases, it might be   necessary to emit a barrier instruction as the last insn to prevent   such scheduling.   Also any insns generated here should have RTX_FRAME_RELATED_P(insn) = 1   so that the debug info generation code can handle them properly.  */voidxstormy16_expand_prologue (){  struct xstormy16_stack_layout layout;  int regno;  rtx insn;  rtx mem_push_rtx;  rtx mem_fake_push_rtx;  const int ifun = xstormy16_interrupt_function_p ();    mem_push_rtx = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);  mem_push_rtx = gen_rtx_MEM (HImode, mem_push_rtx);  mem_fake_push_rtx = gen_rtx_PRE_INC (Pmode, stack_pointer_rtx);  mem_fake_push_rtx = gen_rtx_MEM (HImode, mem_fake_push_rtx);      layout = xstormy16_compute_stack_layout ();  /* Save the argument registers if necessary.  */  if (layout.stdarg_save_size)    for (regno = FIRST_ARGUMENT_REGISTER; 	 regno < FIRST_ARGUMENT_REGISTER + NUM_ARGUMENT_REGISTERS;	 regno++)      {	rtx reg = gen_rtx_REG (HImode, regno);	insn = emit_move_insn (mem_push_rtx, reg);	RTX_FRAME_RELATED_P (insn) = 1;	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,					      gen_rtx_SET (VOIDmode,							   mem_fake_push_rtx,							   reg),					      REG_NOTES (insn));      }    /* Push each of the registers to save.  */  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)    if (REG_NEEDS_SAVE (regno, ifun))      {	rtx reg = gen_rtx_REG (HImode, regno);	insn = emit_move_insn (mem_push_rtx, reg);	RTX_FRAME_RELATED_P (insn) = 1;	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,					      gen_rtx_SET (VOIDmode,							   mem_fake_push_rtx,							   reg),					      REG_NOTES (insn));      }  /* It's just possible that the SP here might be what we need for     the new FP...  */  if (frame_pointer_needed && layout.sp_minus_fp == layout.locals_size)    {      insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);      RTX_FRAME_RELATED_P (insn) = 1;    }  /* Allocate space for local variables.  */  if (layout.locals_size)    {      insn = emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx,				     GEN_INT (layout.locals_size));      RTX_FRAME_RELATED_P (insn) = 1;    }  /* Set up the frame pointer, if required.  */  if (frame_pointer_needed && layout.sp_minus_fp != layout.locals_size)    {      insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);      RTX_FRAME_RELATED_P (insn) = 1;      if (layout.sp_minus_fp)	{

⌨️ 快捷键说明

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