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

📄 out-i860.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Subroutines for insn-output.c for Intel 860   Copyright (C) 1989 Free Software Foundation, Inc.   Derived from out-sparc.c.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING.  If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  *//* Global variables for machine-dependend things.  *//* This should go away if we pass floats to regs via   the stack instead of the frame, and if we learn how   to renumber all the registers when we don't do a save (hard!).  */extern int frame_pointer_needed;static rtx find_addr_reg ();/* Return non-zero only if OP is a register of mode MODE,   or const0_rtx.  */intreg_or_0_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (op == const0_rtx || register_operand (op, mode)	  || op == CONST0_RTX (mode));}/* Return non-zero if this pattern, can be evaluated safely, even if it   was not asked for.  */intsafe_insn_src_p (op, mode)     rtx op;     enum machine_mode mode;{  /* Just experimenting.  */  /* No floating point src is safe if it contains an arithmetic     operation, since that operation may trap.  */  switch (GET_CODE (op))    {    case CONST_INT:    case LABEL_REF:    case SYMBOL_REF:    case CONST:      return 1;    case REG:      return 1;    case MEM:      return CONSTANT_ADDRESS_P (XEXP (op, 0));      /* We never need to negate or complement constants.  */    case NEG:      return (mode != SFmode && mode != DFmode);    case NOT:    case ZERO_EXTEND:      return 1;    case EQ:    case NE:    case LT:    case GT:    case LE:    case GE:    case LTU:    case GTU:    case LEU:    case GEU:    case MINUS:    case PLUS:      return (mode != SFmode && mode != DFmode);    case AND:    case IOR:    case XOR:    case LSHIFT:    case ASHIFT:    case ASHIFTRT:    case LSHIFTRT:      if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))	  || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))	return 0;      return 1;    default:      return 0;    }}/* Return 1 if REG is clobbered in IN.   Return 2 if REG is used in IN.    Return 3 if REG is both used and clobbered in IN.   Return 0 if neither.  */static intreg_clobbered_p (reg, in)     rtx reg;     rtx in;{  register enum rtx_code code;  if (in == 0)    return 0;  code = GET_CODE (in);  if (code == SET || code == CLOBBER)    {      rtx dest = SET_DEST (in);      int set = 0;      int used = 0;      while (GET_CODE (dest) == STRICT_LOW_PART	     || GET_CODE (dest) == SUBREG	     || GET_CODE (dest) == SIGN_EXTRACT	     || GET_CODE (dest) == ZERO_EXTRACT)	dest = XEXP (dest, 0);      if (dest == reg)	set = 1;      else if (GET_CODE (dest) == REG	       && refers_to_regno_p (REGNO (reg),				     REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),				     SET_DEST (in), 0))	{	  set = 1;	  /* Anything that sets just part of the register	     is considered using as well as setting it.	     But note that a straight SUBREG of a single-word value	     clobbers the entire value.   */	  if (dest != SET_DEST (in)	      && ! (GET_CODE (SET_DEST (in)) == SUBREG		    || UNITS_PER_WORD >= GET_MODE_SIZE (GET_MODE (dest))))	    used = 1;	}      if (code == SET)	{	  if (set)	    used = refers_to_regno_p (REGNO (reg),				      REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),				      SET_SRC (in), 0);	  else	    used = refers_to_regno_p (REGNO (reg),				      REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),				      in, 0);	}      return set + used * 2;    }  if (refers_to_regno_p (REGNO (reg),			 REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),			 in, 0))    return 2;  return 0;}/* Return non-zero if OP can be written to without screwing up   GCC's model of what's going on.  It is assumed that this operand   appears in the dest position of a SET insn in a conditional   branch's delay slot.  AFTER is the label to start looking from.  */intoperand_clobbered_before_used_after (op, after)     rtx op;     rtx after;{  extern char call_used_regs[];  /* Just experimenting.  */  if (GET_CODE (op) == CC0)    return 1;  if (GET_CODE (op) == REG)    {      rtx insn;      if (op == stack_pointer_rtx)	return 0;      /* Scan forward from the label, to see if the value of OP	 is clobbered before the first use.  */      for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn))	{	  if (GET_CODE (insn) == NOTE)	    continue;	  if (GET_CODE (insn) == INSN	      || GET_CODE (insn) == JUMP_INSN	      || GET_CODE (insn) == CALL_INSN)	    {	      switch (reg_clobbered_p (op, PATTERN (insn)))		{		default:		  return 0;		case 1:		  return 1;		case 0:		  break;		}	    }	  /* If we reach another label without clobbering OP,	     then we cannot safely write it here.  */	  else if (GET_CODE (insn) == CODE_LABEL)	    return 0;	  if (GET_CODE (insn) == JUMP_INSN)	    {	      if (condjump_p (insn))		return 0;	      /* This is a jump insn which has already		 been mangled.  We can't tell what it does.  */	      if (GET_CODE (PATTERN (insn)) == PARALLEL)		return 0;	      if (! JUMP_LABEL (insn))		return 0;	      /* Keep following jumps.  */	      insn = JUMP_LABEL (insn);	    }	}      return 1;    }  /* In both of these cases, the first insn executed     for this op will be a orh whatever%h,r0,r31,     which is tolerable.  */  if (GET_CODE (op) == MEM)    return (CONSTANT_ADDRESS_P (XEXP (op, 0)));  return 0;}/* Return non-zero if this pattern, as a source to a "SET",   is known to yield an instruction of unit size.  */intsingle_insn_src_p (op, mode)     rtx op;     enum machine_mode mode;{  switch (GET_CODE (op))    {    case CONST_INT:      /* This is not always a single insn src, technically,	 but output_delayed_branch knows how to deal with it.  */      return 1;    case SYMBOL_REF:    case CONST:      /* This is not a single insn src, technically,	 but output_delayed_branch knows how to deal with it.  */      return 1;    case REG:      return 1;    case MEM:      return 1;      /* We never need to negate or complement constants.  */    case NEG:      return (mode != DFmode);    case NOT:    case ZERO_EXTEND:      return 1;    case PLUS:    case MINUS:      /* Detect cases that require multiple instructions.  */      if (CONSTANT_P (XEXP (op, 1))	  && !(GET_CODE (XEXP (op, 1)) == CONST_INT	       && SMALL_INT (XEXP (op, 1))))	return 0;    case EQ:    case NE:    case LT:    case GT:    case LE:    case GE:    case LTU:    case GTU:    case LEU:    case GEU:      /* Not doing floating point, since they probably	 take longer than the branch slot they might fill.  */      return (mode != SFmode && mode != DFmode);    case AND:      if (GET_CODE (XEXP (op, 1)) == NOT)	{	  rtx arg = XEXP (XEXP (op, 1), 0);	  if (CONSTANT_P (arg)	      && !(GET_CODE (arg) == CONST_INT		   && (SMALL_INT (arg)		       || INTVAL (arg) & 0xffff == 0)))	    return 0;	}    case IOR:    case XOR:      /* Both small and round numbers take one instruction;	 others take two.  */      if (CONSTANT_P (XEXP (op, 1))	  && !(GET_CODE (XEXP (op, 1)) == CONST_INT	       && (SMALL_INT (XEXP (op, 1))		   || INTVAL (XEXP (op, 1)) & 0xffff == 0)))	return 0;    case LSHIFT:    case ASHIFT:    case ASHIFTRT:    case LSHIFTRT:      return 1;    case SUBREG:      if (SUBREG_WORD (op) != 0)	return 0;      return single_insn_src_p (SUBREG_REG (op), mode);      /* Not doing floating point, since they probably	 take longer than the branch slot they might fill.  */    case FLOAT_EXTEND:    case FLOAT_TRUNCATE:    case FLOAT:    case FIX:    case UNSIGNED_FLOAT:    case UNSIGNED_FIX:      return 0;    default:      return 0;    }}/* Nonzero only if this *really* is a single insn operand.  */intstrict_single_insn_op_p (op, mode)     rtx op;     enum machine_mode mode;{  if (mode == VOIDmode)    mode = GET_MODE (op);  switch (GET_CODE (op))    {    case CC0:      return 1;    case CONST_INT:      if (SMALL_INT (op))	return 1;      /* We can put this set insn into delay slot, because this is one	 insn; `orh'.  */      if ((INTVAL (op) & 0xffff) == 0)	return 1;      return 0;    case SYMBOL_REF:      return 0;    case REG:#if 0      /* This loses when moving an freg to a general reg.  */      return HARD_REGNO_NREGS (REGNO (op), mode) == 1;#endif      return (mode != DFmode && mode != DImode);    case MEM:      if (! CONSTANT_ADDRESS_P (XEXP (op, 0)))	return (mode != DFmode && mode != DImode);      return 0;      /* We never need to negate or complement constants.  */    case NEG:      return (mode != DFmode);    case NOT:    case ZERO_EXTEND:      return 1;    case PLUS:    case MINUS:      /* Detect cases that require multiple instructions.  */      if (CONSTANT_P (XEXP (op, 1))	  && !(GET_CODE (XEXP (op, 1)) == CONST_INT	       && SMALL_INT (XEXP (op, 1))))	return 0;    case EQ:    case NE:    case LT:    case GT:    case LE:    case GE:    case LTU:    case GTU:    case LEU:    case GEU:      return 1;    case AND:      if (GET_CODE (XEXP (op, 1)) == NOT)	{	  rtx arg = XEXP (XEXP (op, 1), 0);	  if (CONSTANT_P (arg)	      && !(GET_CODE (arg) == CONST_INT		   && (SMALL_INT (arg)		       || INTVAL (arg) & 0xffff == 0)))	    return 0;	}    case IOR:    case XOR:      /* Both small and round numbers take one instruction;	 others take two.  */      if (CONSTANT_P (XEXP (op, 1))	  && !(GET_CODE (XEXP (op, 1)) == CONST_INT	       && (SMALL_INT (XEXP (op, 1))		   || INTVAL (XEXP (op, 1)) & 0xffff == 0)))	return 0;    case LSHIFT:    case ASHIFT:    case ASHIFTRT:    case LSHIFTRT:      return 1;    case SUBREG:      if (SUBREG_WORD (op) != 0)	return 0;      return strict_single_insn_op_p (SUBREG_REG (op), mode);    case SIGN_EXTEND:      if (GET_CODE (XEXP (op, 0)) == MEM	  && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0)))	return 1;      return 0;      /* Not doing floating point, since they probably	 take longer than the branch slot they might fill.  */    case FLOAT_EXTEND:    case FLOAT_TRUNCATE:    case FLOAT:    case FIX:    case UNSIGNED_FLOAT:    case UNSIGNED_FIX:      return 0;    default:      return 0;    }}/* Return truth value of whether OP is a relational operator.  */intrelop (op, mode)     rtx op;     enum machine_mode mode;{  switch (GET_CODE (op))    {    case EQ:    case NE:    case GT:    case GE:    case LT:    case LE:    case GTU:    case GEU:    case LTU:    case LEU:      return 1;    }  return 0;}/* Return truth value of whether OP can be used as an operands in a three   address add/subtract insn (such as add %o1,7,%l2) of mode MODE.  */intarith_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, mode)	  || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));}/* Return 1 if OP is a valid first operand for a logical insn of mode MODE.  */intlogic_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, mode)	  || (GET_CODE (op) == CONST_INT && LOGIC_INT (op)));}

⌨️ 快捷键说明

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