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

📄 out-sparc.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Subroutines for insn-output.c for Sun SPARC.   Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc.   Contributed by Michael Tiemann (tiemann@mcc.com)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 ();rtx next_real_insn_no_labels ();/* 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));}/* Return non-zero if INSN is a conditional insn with a predicate   valid after an addcc or subcc instruction.  */intignore_overflow_conditional_p (insn)     rtx insn;{  rtx x = SET_SRC (PATTERN (insn));  RTX_CODE code;  if (GET_CODE (x) == IF_THEN_ELSE)    x = XEXP (x, 0);  code = GET_CODE (x);  return code == EQ || code == NE || code == GE || code == LT;}/* 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:      return 1;    case COMPARE:    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 0 if REG is used in IN (other than being clobbered).   Return 2 if REG does not appear in IN.  */static intreg_clobbered_p (reg, in)     rtx reg;     rtx in;{  register char *fmt;  register int i, result = 0;  register enum rtx_code code;  if (in == 0)    return 2;  code = GET_CODE (in);  switch (code)    {      /* Let these fail out quickly.  */    case CONST_INT:    case SYMBOL_REF:    case CONST:      return 2;    case SUBREG:      if (SUBREG_WORD (in) != 0)	in = gen_rtx (REG, SImode, REGNO (SUBREG_REG (in)) + SUBREG_WORD (in));      else	in = SUBREG_REG (in);    case REG:      if (in == reg	  || refers_to_regno_p (REGNO (reg),				REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),				in, 0))	return 0;      return 2;    case SET:      if (SET_SRC (in) == reg	  || refers_to_regno_p (REGNO (reg),				REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),				SET_SRC (in), 0))	return 0;      if (SET_DEST (in) == reg)	return 1;      if (refers_to_regno_p (REGNO (reg),			     REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),			     SET_DEST (in), 0))	if (GET_CODE (SET_DEST (in)) == REG	    || GET_CODE (SET_DEST (in)) == SUBREG)	  return 1;	else	  return 0;      return 2;    case USE:      if (XEXP (in, 0) == reg	  || refers_to_regno_p (REGNO (reg),				REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),				XEXP (in, 0), 0))	return 0;      return 2;    case CLOBBER:      if (XEXP (in, 0) == reg)	return 1;      /* If the CLOBBER expression is a SUBREG, accept that as a	 clobber.  But if it is some expression based on this register,	 that is like a USE as far as this register is concerned,	 so we won't take it.  */      if (refers_to_regno_p (REGNO (reg),			     REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),			     XEXP (in, 0), 0))	if (GET_CODE (XEXP (in, 0)) == REG	    || GET_CODE (XEXP (in, 0)) == SUBREG)	  return 1;	else	  return 0;      return 2;    }  fmt = GET_RTX_FORMAT (code);  result = 2;  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)    {      if (fmt[i] == 'E')	{	  register int j;	  for (j = XVECLEN (in, i) - 1; j >= 0; j--)	    switch (reg_clobbered_p (reg, XVECEXP (in, i, j)))	      {	      case 0:		return 0;	      case 2:		continue;	      case 1:		result = 1;		break;	      }	}      else if (fmt[i] == 'e')	switch (reg_clobbered_p (reg, XEXP (in, i)))	  {	  case 0:	    return 0;	  case 2:	    continue;	  case 1:	    result = 1;	    break;	  }    }  return result;}/* 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;      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)))		{		case 0:		  return 0;		case 2:		  break;		case 1:		  return 1;		}	      if (dead_or_set_p (insn, op))		return 1;	    }	  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 sethi %hi(whatever),%g1,     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:#if 1      /* This is not always a single insn src, technically,	 but output_delayed_branch knows how to deal with it.  */      return 1;#else      if (SMALL_INT (op))	return 1;      /* We can put this set insn into delay slot, because this is one	 insn; 'sethi'.  */      if ((INTVAL (op) & 0x3ff) == 0)	return 1;      /* This is not a single insn src, technically,	 but output_delayed_branch knows how to deal with it.  */      return 1;#endif#if 1    case SYMBOL_REF:      /* This is not a single insn src, technically,	 but output_delayed_branch knows how to deal with it.  */      return 1;#else      return 0;#endif    case REG:      return 1;    case MEM:#if 0      /* This is not a single insn src, technically,	 but output_delayed_branch knows how to deal with it.  */      if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF)	return 0;#endif      return 1;      /* We never need to negate or complement constants.  */    case NEG:      return (mode != DFmode);    case NOT:      return 1;    case COMPARE:    case MINUS:      /* If the target is cc0, then these insns will take	 two insns (one being a nop).  */      if (mode != SFmode && mode != DFmode)	return 0;    case PLUS:    case AND:    case IOR:    case XOR:      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;    case LSHIFT:    case ASHIFT:    case ASHIFTRT:    case LSHIFTRT:      if (GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))	return 0;      if (GET_CODE (XEXP (op, 1)) != REG	  && (GET_CODE (XEXP (op, 1)) != SUBREG	      || GET_CODE (SUBREG_REG (XEXP (op, 1))) != REG))	return 0;      return 1;    case SUBREG:      if (SUBREG_WORD (op) != 0)	return 0;      return single_insn_src_p (SUBREG_REG (op), mode);    case SIGN_EXTEND:    case ZERO_EXTEND:      /* Lazy... could check for more cases.  */      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;    }}/* This extra test must be done to verify that a move insn   really is just one assembler insn.  */intsingle_insn_extra_test (dest, src)     rtx dest, src;{  /* Moves between FP regs and CPU regs are two insns.  */  return (!(GET_CODE (src) == REG	    && GET_CODE (dest) == REG	    && (FP_REG_P (src) != FP_REG_P (dest))));}/* 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; 'sethi'.  */      if ((INTVAL (op) & 0x3ff) == 0)	return 1;      return 0;    case SYMBOL_REF:      return 0;    case REG:      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:      return 1;    case COMPARE:    case MINUS:      /* If the target is cc0, then these insns will take	 two insns (one being a nop).  */      return (mode != SFmode && mode != DFmode);    case PLUS:    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;    case SUBREG:      if (SUBREG_WORD (op) != 0)	return 0;      return strict_single_insn_op_p (SUBREG_REG (op), mode);    case SIGN_EXTEND:    case ZERO_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;

⌨️ 快捷键说明

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