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

📄 i860.c

📁 Mac OS X 10.4.9 for x86 Source Code gcc 实现源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Subroutines for insn-output.c for Intel i860   Copyright (C) 1989, 1991, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,   2005   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 GCC.GCC 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.GCC 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 GCC; 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 "system.h"#include "coretypes.h"#include "tm.h"#include "flags.h"#include "rtl.h"#include "tree.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "output.h"#include "recog.h"#include "insn-attr.h"#include "function.h"#include "expr.h"#include "optabs.h"#include "toplev.h"#include "tm_p.h"#include "target.h"#include "target-def.h"#include "langhooks.h"#include "tree-gimple.h"static rtx find_addr_reg (rtx);#ifndef I860_REG_PREFIX#define I860_REG_PREFIX ""#endifconst char *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 nonzero if this pattern, can be evaluated safely, even if it   was not asked for.  */intsafe_insn_src_p (rtx op, enum machine_mode mode){  /* Just experimenting.  */  /* No floating point source 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 none of the above.  */static intreg_clobbered_p (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) == 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 nonzero 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 (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 nonzero only if OP is a register of mode MODE,   or const0_rtx.  */intreg_or_0_operand (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 (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 (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 (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 (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 (rtx op, enum machine_mode mode){  return (register_operand (op, mode)	  || (GET_CODE (op) == CONST_INT	      && (unsigned) INTVAL (op) < 0x20));}/* Return 1 if OP is an indexed memory reference of mode MODE.  */intindexed_operand (rtx op, enum machine_mode mode){  return (GET_CODE (op) == MEM && GET_MODE (op) == mode	  && GET_CODE (XEXP (op, 0)) == PLUS	  && GET_MODE (XEXP (op, 0)) == SImode	  && register_operand (XEXP (XEXP (op, 0), 0), SImode)	  && register_operand (XEXP (XEXP (op, 0), 1), SImode));}/* Return 1 if OP is a suitable source operand for a load insn   with mode MODE.  */intload_operand (rtx op, enum machine_mode mode){  return (memory_operand (op, mode) || indexed_operand (op, mode));}/* Return truth value of whether OP is an integer which fits the   range constraining immediate operands in add/subtract insns.  */intsmall_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){  return (GET_CODE (op) == CONST_INT && SMALL_INT (op));}/* Return truth value of whether OP is an integer which fits the   range constraining immediate operands in logic insns.  */intlogic_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){  return (GET_CODE (op) == CONST_INT && LOGIC_INT (op));}/* Test for a valid operand for a call instruction.   Don't allow the arg pointer register or virtual regs   since they may change into reg + const, which the patterns   can't handle yet.  */intcall_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){  if (GET_CODE (op) == MEM      && (CONSTANT_ADDRESS_P (XEXP (op, 0))	  || (GET_CODE (XEXP (op, 0)) == REG	      && XEXP (op, 0) != arg_pointer_rtx	      && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER		   && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))    return 1;  return 0;}/* Return the best assembler insn template   for moving operands[1] into operands[0] as a fullword.  */static const char *singlemove_string (rtx *operands){  if (GET_CODE (operands[0]) == MEM)    {      if (GET_CODE (operands[1]) != MEM)	if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))	  {	    if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)		   && (cc_prev_status.flags & CC_HI_R31_ADJ)		   && cc_prev_status.mdep == XEXP (operands[0], 0)))	      {		CC_STATUS_INIT;	        output_asm_insn ("orh %h0,%?r0,%?r31", operands);	      }	    cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;	    cc_status.mdep = XEXP (operands[0], 0);	    return "st.l %r1,%L0(%?r31)";	  }	else	  return "st.l %r1,%0";      else	abort ();#if 0	{	  rtx xoperands[2];	  cc_status.flags &= ~CC_F0_IS_0;	  xoperands[0] = gen_rtx_REG (SFmode, 32);	  xoperands[1] = operands[1];	  output_asm_insn (singlemove_string (xoperands), xoperands);	  xoperands[1] = xoperands[0];	  xoperands[0] = operands[0];	  output_asm_insn (singlemove_string (xoperands), xoperands);	  return "";	}#endif    }  if (GET_CODE (operands[1]) == MEM)    {      if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))	{	  if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)

⌨️ 快捷键说明

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