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

📄 sh.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 4 页
字号:
     int rn;{  rtx x;  x = emit_insn (gen_pop (gen_rtx (REG, SImode, rn)));  REG_NOTES (x) = gen_rtx (EXPR_LIST, REG_INC,			   gen_rtx(REG, SImode, STACK_POINTER_REGNUM), 0);}/* Generate code to push the regs specified in the mask, and return   the number of bytes the insns take.  */static voidpush_regs (mask)     int mask;{  int i;  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)    if (mask & (1 << i))      push (i);}/* Work out the registers which need to be saved, both as a mask and a   count.   If doing a pragma interrupt function, then push all regs used by the   function, and if we call another function (we can tell by looking at PR),   make sure that all the regs it clobbers are safe too.  */static intcalc_live_regs (count_ptr)     int *count_ptr;{  int reg;  int live_regs_mask = 0;  int count = 0;  for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++)    {      if (pragma_interrupt && ! pragma_trapa)	{	  /* Need to save all the regs ever live.  */	  if ((regs_ever_live[reg]	       || (call_used_regs[reg] && regs_ever_live[PR_REG]))	      && reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM	      && reg != T_REG && reg != GBR_REG)	    {	      live_regs_mask |= 1 << reg;	      count++;	    }	}      else	{	  /* Only push those regs which are used and need to be saved.  */	  if (regs_ever_live[reg] && ! call_used_regs[reg])	    {	      live_regs_mask |= (1 << reg);	      count++;	    }	}    }  *count_ptr = count;  return live_regs_mask;}/* Code to generate prologue and epilogue sequences */voidsh_expand_prologue (){  int live_regs_mask;  int d, i;  live_regs_mask = calc_live_regs (&d);  /* We have pretend args if we had an object sent partially in registers     and partially on the stack, e.g. a large structure.  */  output_stack_adjust (-current_function_pretend_args_size, stack_pointer_rtx);  extra_push = 0;  /* This is set by SETUP_VARARGS to indicate that this is a varargs     routine.  Clear it here so that the next function isn't affected.  */  if (current_function_anonymous_args)    {      current_function_anonymous_args = 0;      /* Push arg regs as if they'd been provided by caller in stack.  */      for (i = 0; i < NPARM_REGS; i++)	{	  int rn = NPARM_REGS + FIRST_PARM_REG - i - 1;	  if (i > (NPARM_REGS - current_function_args_info		   - current_function_varargs))	    break;	  push (rn);	  extra_push += 4;	}    }  push_regs (live_regs_mask);  output_stack_adjust (-get_frame_size (), stack_pointer_rtx);  if (frame_pointer_needed)    emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));}voidsh_expand_epilogue (){  int live_regs_mask;  int d, i;  live_regs_mask = calc_live_regs (&d);  if (frame_pointer_needed)    {      /* We deliberately make the add dependent on the frame_pointer,	 to ensure that instruction scheduling won't move the stack pointer	 adjust before instructions reading from the frame.  This can fail	 if there is an interrupt which then writes to the stack.  */      output_stack_adjust (get_frame_size (), frame_pointer_rtx);      emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx));    }  else    output_stack_adjust (get_frame_size (), stack_pointer_rtx);  /* Pop all the registers.  */  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)    {      int j = (FIRST_PSEUDO_REGISTER - 1) - i;      if (live_regs_mask & (1 << j))	pop (j);    }  output_stack_adjust (extra_push + current_function_pretend_args_size,		       stack_pointer_rtx);}/* Clear variables at function end.  */voidfunction_epilogue (stream, size)     FILE *stream;     int size;{  pragma_interrupt = pragma_trapa = 0;}/* Define the offset between two registers, one to be eliminated, and   the other its replacement, at the start of a routine.  */intinitial_elimination_offset (from, to)     int from;     int to;{  int regs_saved;  int total_saved_regs_space;  int total_auto_space = get_frame_size ();  calc_live_regs (&regs_saved);  total_saved_regs_space = (regs_saved) * 4;  if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)    return total_saved_regs_space + total_auto_space;  if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)    return total_saved_regs_space + total_auto_space;  /* Initial gap between fp and sp is 0.  */  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)    return 0;  abort ();}/* Handle machine specific pragmas to be semi-compatible with Hitachi   compiler.  */inthandle_pragma (file)     FILE *file;{  int c;  char pbuf[200];  int psize = 0;  c = getc (file);  while (c == ' ' || c == '\t')    c = getc (file);  if (c == '\n' || c == EOF)    return c;  while (psize < sizeof (pbuf) - 1 && c != '\n')    {      pbuf[psize++] = c;      if (psize == 9 && strncmp (pbuf, "interrupt", 9) == 0)	{	  pragma_interrupt = 1;	  return ' ';	}      if (psize == 5 && strncmp (pbuf, "trapa", 5) == 0)	{	  pragma_interrupt = pragma_trapa = 1;	  return ' ';	}      c = getc (file);    }  return c;}/* Predicates used by the templates.  *//* Returns 1 if OP is MACL, MACH or PR.  The input must be a REG rtx.   Used only in general_movsrc_operand.  */intsystem_reg_operand (op, mode)     rtx op;     enum machine_mode mode;{  switch (REGNO (op))    {    case PR_REG:    case MACL_REG:    case MACH_REG:      return 1;    }  return 0;}/* Returns 1 if OP can be source of a simple move operation.   Same as general_operand, but a LABEL_REF is valid, PRE_DEC is   invalid as are subregs of system registers.  */intgeneral_movsrc_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == MEM)    {      rtx inside = XEXP (op, 0);      if (GET_CODE (inside) == CONST)	inside = XEXP (inside, 0);      if (GET_CODE (inside) == LABEL_REF)	return 1;      if (GET_CODE (inside) == PLUS	  && GET_CODE (XEXP (inside, 0)) == LABEL_REF	  && GET_CODE (XEXP (inside, 1)) == CONST_INT)	return 1;      /* Only post inc allowed.  */      if (GET_CODE (inside) == PRE_DEC)	return 0;    }  if ((mode == QImode || mode == HImode)      && (GET_CODE (op) == SUBREG	  && GET_CODE (XEXP (op, 0)) == REG	  && system_reg_operand (XEXP (op, 0), mode)))    return 0;  return general_operand (op, mode);}/* Returns 1 if OP can be a destination of a move.   Same as general_operand, but no preinc allowed.  */intgeneral_movdst_operand (op, mode)     rtx op;     enum machine_mode mode;{  /* Only pre dec allowed.  */  if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == POST_INC)    return 0;  return general_operand (op, mode);}/* Returns 1 if OP is a normal arithmetic register.  */intarith_reg_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (register_operand (op, mode))    {      if (GET_CODE (op) == REG)	return (REGNO (op) != T_REG		&& REGNO (op) != PR_REG		&& REGNO (op) != MACH_REG		&& REGNO (op) != MACL_REG);      return 1;    }  return 0;}/* Returns 1 if OP is a valid source operand for an arithmetic insn.  */intarith_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (arith_reg_operand (op, mode))    return 1;  if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_I (INTVAL (op)))    return 1;  return 0;}/* Returns 1 if OP is a valid source operand for a compare insn.  */intarith_reg_or_0_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (arith_reg_operand (op, mode))    return 1;  if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_N (INTVAL (op)))    return 1;  return 0;}/* Returns 1 if OP is a valid source operand for a logical operation.  */intlogical_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (arith_reg_operand (op, mode))    return 1;  if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_L (INTVAL (op)))    return 1;  return 0;}/* Determine where to put an argument to a function.   Value is zero to push the argument on the stack,   or a hard register in which to store the argument.   MODE is the argument's machine mode.   TYPE is the data type of the argument (as a tree).    This is null for libcalls where that information may    not be available.   CUM is a variable of type CUMULATIVE_ARGS which gives info about    the preceding args and about the function being called.   NAMED is nonzero if this argument is a named parameter    (otherwise it is an extra parameter matching an ellipsis).  */rtxsh_function_arg (cum, mode, type, named)     CUMULATIVE_ARGS cum;     enum machine_mode mode;     tree type;     int named;{  if (named)    {      int rr = (ROUND_REG (cum, mode));      if (rr < NPARM_REGS)	return ((type == 0 || ! TREE_ADDRESSABLE (type))		? gen_rtx (REG, mode, FIRST_PARM_REG + rr) : 0);    }  return 0;}/* For an arg passed partly in registers and partly in memory,   this is the number of registers used.   For args passed entirely in registers or entirely in memory, zero.   Any arg that starts in the first 4 regs but won't entirely fit in them   needs partial registers on the SH.  */intsh_function_arg_partial_nregs (cum, mode, type, named)     CUMULATIVE_ARGS cum;     enum machine_mode mode;     tree type;     int named;{  if (cum < NPARM_REGS)    {      if ((type == 0 || ! TREE_ADDRESSABLE (type))	  && (cum + (mode == BLKmode		     ? ROUND_ADVANCE (int_size_in_bytes (type))		     : ROUND_ADVANCE (GET_MODE_SIZE (mode))) - NPARM_REGS > 0))	return NPARM_REGS - cum;    }  return 0;}/* Return non-zero if REG is not used after INSN.   We assume REG is a reload reg, and therefore does   not live past labels or calls or jumps.  */intreg_unused_after (reg, insn)     rtx reg;     rtx insn;{  enum rtx_code code;  rtx set;  /* If the reg is set by this instruction, then it is safe for our     case.  Disregard the case where this is a store to memory, since     we are checking a register used in the store address.  */  set = single_set (insn);  if (set && GET_CODE (SET_DEST (set)) != MEM      && reg_overlap_mentioned_p (reg, SET_DEST (set)))    return 1;  while (insn = NEXT_INSN (insn))    {      code = GET_CODE (insn);#if 0      /* If this is a label that existed before reload, then the register	 if dead here.  However, if this is a label added by reorg, then	 the register may still be live here.  We can't tell the difference,	 so we just ignore labels completely.  */      if (code == CODE_LABEL)	return 1;      /* else */#endif      /* If this is a sequence, we must handle them all at once.	 We could have for instance a call that sets the target register,	 and a insn in a delay slot that uses the register.  In this case,	 we must return 0.  */      if (code == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)	{	  int i;	  int retval = 0;	  for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)	    {	      rtx this_insn = XVECEXP (PATTERN (insn), 0, i);	      rtx set = single_set (this_insn);	      if (GET_CODE (this_insn) == CALL_INSN)		code = CALL_INSN;	      if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))		return 0;	      if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))		{		  if (GET_CODE (SET_DEST (set)) != MEM)		    retval = 1;		  else		    return 0;		}	      if (set == 0		  && reg_overlap_mentioned_p (reg, PATTERN (this_insn)))		return 0;	    }	  if (retval == 1)	    return 1;	}      else if (GET_RTX_CLASS (code) == 'i')	{	  rtx set = single_set (insn);	  if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))	    return 0;	  if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))	    return GET_CODE (SET_DEST (set)) != MEM;	  if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))	    return 0;	}      if (code == CALL_INSN && call_used_regs[REGNO (reg)])	return 1;    }  return 1;}

⌨️ 快捷键说明

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