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

📄 i860.c

📁 gcc-2.95.3 Linux下最常用的C编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Subroutines for insn-output.c for Intel 860   Copyright (C) 1989, 91, 97, 98, 1999 Free Software Foundation, Inc.   Derived from sparc.c.   Written by Richard Stallman (rms@ai.mit.edu).   Hacked substantially by Ron Guilmette (rfg@netcom.com) to cater   to the whims of the System V Release 4 assembler.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 2, 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, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA.  */#include "config.h"#include <stdio.h>#include "flags.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "insn-flags.h"#include "output.h"#include "recog.h"#include "insn-attr.h"static rtx find_addr_reg ();#ifndef I860_REG_PREFIX#define I860_REG_PREFIX ""#endifchar *i860_reg_prefix = I860_REG_PREFIX;/* Save information from a "cmpxx" operation until the branch is emitted.  */rtx i860_compare_op0, i860_compare_op1;/* 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 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;{  /* 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 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;    }}/* 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 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)));}/* Return 1 if OP is a valid first operand for a shift insn of mode MODE.  */intshift_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, mode)          || (GET_CODE (op) == CONST_INT));}/* Return 1 if OP is a valid first operand for either a logical insn   or an add insn of mode MODE.  */intcompare_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, mode)	  || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op)));}/* Return truth value of whether OP can be used as the 5-bit immediate   operand of a bte or btne insn.  */intbte_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, mode)	  || (GET_CODE (op) == CONST_INT	      && (unsigned) INTVAL (op) < 0x20));

⌨️ 快捷键说明

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