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

📄 sparc.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Subroutines for insn-output.c for Sun SPARC.   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.   Contributed by Michael Tiemann (tiemann@cygnus.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 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */#include <stdio.h>#include "config.h"#include "tree.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 "insn-attr.h"#include "flags.h"#include "expr.h"#include "recog.h"/* Global variables for machine-dependent things.  *//* Save the operands last given to a compare for use when we   generate a scc or bcc insn.  */rtx sparc_compare_op0, sparc_compare_op1;/* We may need an epilogue if we spill too many registers.   If this is non-zero, then we branch here for the epilogue.  */static rtx leaf_label;#ifdef LEAF_REGISTERS/* Vector to say how input registers are mapped to output   registers.  FRAME_POINTER_REGNUM cannot be remapped by   this function to eliminate it.  You must use -fomit-frame-pointer   to get that.  */char leaf_reg_remap[] ={ 0, 1, 2, 3, 4, 5, 6, 7,  -1, -1, -1, -1, -1, -1, 14, -1,  -1, -1, -1, -1, -1, -1, -1, -1,  8, 9, 10, 11, 12, 13, -1, 15,  32, 33, 34, 35, 36, 37, 38, 39,  40, 41, 42, 43, 44, 45, 46, 47,  48, 49, 50, 51, 52, 53, 54, 55,  56, 57, 58, 59, 60, 61, 62, 63};char leaf_reg_backmap[] ={ 0, 1, 2, 3, 4, 5, 6, 7,  24, 25, 26, 27, 28, 29, 14, 31,  -1, -1, -1, -1, -1, -1, -1, -1,  -1, -1, -1, -1, -1, -1, -1, -1,  32, 33, 34, 35, 36, 37, 38, 39,  40, 41, 42, 43, 44, 45, 46, 47,  48, 49, 50, 51, 52, 53, 54, 55,  56, 57, 58, 59, 60, 61, 62, 63};#endif/* Global variables set by FUNCTION_PROLOGUE.  *//* Size of frame.  Need to know this to emit return insns from   leaf procedures.  */int apparent_fsize;int actual_fsize;/* Name of where we pretend to think the frame pointer points.   Normally, this is "%fp", but if we are in a leaf procedure,   this is "%sp+something".  */char *frame_base_name;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;{  if (op == const0_rtx || register_operand (op, mode))    return 1;  if (GET_CODE (op) == CONST_DOUBLE      && CONST_DOUBLE_HIGH (op) == 0      && CONST_DOUBLE_LOW (op) == 0)    return 1;  return 0;}/* Nonzero if OP can appear as the dest of a RESTORE insn.  */intrestore_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == REG && GET_MODE (op) == mode	  && (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32)));}/* PC-relative call insn on SPARC is independent of `memory_operand'.  */intcall_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) != MEM)    abort ();  op = XEXP (op, 0);  return (REG_P (op) || CONSTANT_P (op));}intcall_operand_address (op, mode)     rtx op;     enum machine_mode mode;{  return (REG_P (op) || CONSTANT_P (op));}/* Returns 1 if OP is either a symbol reference or a sum of a symbol   reference and a constant.  */intsymbolic_operand (op, mode)     register rtx op;     enum machine_mode mode;{  switch (GET_CODE (op))    {    case SYMBOL_REF:    case LABEL_REF:      return 1;    case CONST:      op = XEXP (op, 0);      return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF	       || GET_CODE (XEXP (op, 0)) == LABEL_REF)	      && GET_CODE (XEXP (op, 1)) == CONST_INT);      /* This clause seems to be irrelevant.  */    case CONST_DOUBLE:      return GET_MODE (op) == mode;    default:      return 0;    }}/* Return truth value of statement that OP is a symbolic memory   operand of mode MODE.  */intsymbolic_memory_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == SUBREG)    op = SUBREG_REG (op);  if (GET_CODE (op) != MEM)    return 0;  op = XEXP (op, 0);  return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST	  || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);}/* Return 1 if the operand is either a register or a memory operand that is   not symbolic.  */intreg_or_nonsymb_mem_operand (op, mode)    register rtx op;    enum machine_mode mode;{  if (register_operand (op, mode))    return 1;  if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))    return 1;  return 0;}intsparc_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (register_operand (op, mode))    return 1;  if (GET_CODE (op) == CONST_INT)    return SMALL_INT (op);  if (GET_MODE (op) != mode)    return 0;  if (GET_CODE (op) == SUBREG)    op = SUBREG_REG (op);  if (GET_CODE (op) != MEM)    return 0;  op = XEXP (op, 0);  if (GET_CODE (op) == LO_SUM)    return (GET_CODE (XEXP (op, 0)) == REG	    && symbolic_operand (XEXP (op, 1), Pmode));  return memory_address_p (mode, op);}intmove_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (mode == DImode && arith_double_operand (op, mode))    return 1;  if (register_operand (op, mode))    return 1;  if (GET_CODE (op) == CONST_INT)    return (SMALL_INT (op) || (INTVAL (op) & 0x3ff) == 0);  if (GET_MODE (op) != mode)    return 0;  if (GET_CODE (op) == SUBREG)    op = SUBREG_REG (op);  if (GET_CODE (op) != MEM)    return 0;  op = XEXP (op, 0);  if (GET_CODE (op) == LO_SUM)    return (register_operand (XEXP (op, 0), Pmode)	    && CONSTANT_P (XEXP (op, 1)));  return memory_address_p (mode, op);}intmove_pic_label (op, mode)     rtx op;     enum machine_mode mode;{  /* Special case for PIC.  */  if (flag_pic && GET_CODE (op) == LABEL_REF)    return 1;  return 0;}/* The rtx for the global offset table which is a special form   that *is* a position independent symbolic constant.  */rtx pic_pc_rtx;/* Ensure that we are not using patterns that are not OK with PIC.  */intcheck_pic (i)     int i;{  switch (flag_pic)    {    case 1:      if (GET_CODE (recog_operand[i]) == SYMBOL_REF	  || (GET_CODE (recog_operand[i]) == CONST	      && ! rtx_equal_p (pic_pc_rtx, recog_operand[i])))	abort ();    case 2:    default:      return 1;    }}/* Return true if X is an address which needs a temporary register when    reloaded while generating PIC code.  */intpic_address_needs_scratch (x)     rtx x;{  /* An address which is a symbolic plus a non SMALL_INT needs a temp reg.  */  if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS      && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT      && ! SMALL_INT (XEXP (XEXP (x, 0), 1)))    return 1;  return 0;}intmemop (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == MEM)    return (mode == VOIDmode || mode == GET_MODE (op));  return 0;}/* Return truth value of whether OP is EQ or NE.  */inteq_or_neq (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == EQ || GET_CODE (op) == NE);}/* Return 1 if this is a comparison operator, but not an EQ, NE, GEU,   or LTU for non-floating-point.  We handle those specially.  */intnormal_comp_operator (op, mode)     rtx op;     enum machine_mode mode;{  enum rtx_code code = GET_CODE (op);  if (GET_RTX_CLASS (code) != '<')    return 0;  if (GET_MODE (XEXP (op, 0)) == CCFPmode      || GET_MODE (XEXP (op, 0)) == CCFPEmode)    return 1;  return (code != NE && code != EQ && code != GEU && code != LTU);}/* Return 1 if this is a comparison operator.  This allows the use of   MATCH_OPERATOR to recognize all the branch insns.  */intnoov_compare_op (op, mode)    register rtx op;    enum machine_mode mode;{  enum rtx_code code = GET_CODE (op);  if (GET_RTX_CLASS (code) != '<')    return 0;  if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode)    /* These are the only branches which work with CC_NOOVmode.  */    return (code == EQ || code == NE || code == GE || code == LT);  return 1;}/* Return 1 if this is a SIGN_EXTEND or ZERO_EXTEND operation.  */intextend_op (op, mode)     rtx op;     enum machine_mode mode;{  return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;}/* Return nonzero if OP is an operator of mode MODE which can set   the condition codes explicitly.  We do not include PLUS and MINUS   because these require CC_NOOVmode, which we handle explicitly.  */intcc_arithop (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == AND      || GET_CODE (op) == IOR      || GET_CODE (op) == XOR)    return 1;  return 0;}/* Return nonzero if OP is an operator of mode MODE which can bitwise   complement its second operand and set the condition codes explicitly.  */intcc_arithopn (op, mode)     rtx op;     enum machine_mode mode;{  /* XOR is not here because combine canonicalizes (xor (not ...) ...)     and (xor ... (not ...)) to (not (xor ...)).   */  return (GET_CODE (op) == AND	  || GET_CODE (op) == IOR);}/* Return truth value of whether OP can be used as an operands in a three   address arithmetic 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 truth value of whether OP is a register or a CONST_DOUBLE.  */intarith_double_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (register_operand (op, mode)	  || (GET_CODE (op) == CONST_DOUBLE	      && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)	      && (unsigned) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000	      && ((CONST_DOUBLE_HIGH (op) == -1		   && (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000)		  || (CONST_DOUBLE_HIGH (op) == 0		      && (CONST_DOUBLE_LOW (op) & 0x1000) == 0)))	  || (GET_CODE (op) == CONST_INT	      && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)	      && (unsigned) (INTVAL (op) + 0x1000) < 0x2000));}/* Return truth value of whether OP is a integer which fits the   range constraining immediate operands in three-address insns.  */intsmall_int (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == CONST_INT && SMALL_INT (op));}/* Return truth value of statement that OP is a call-clobbered register.  */intclobbered_register (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);}/* X and Y are two things to compare using CODE.  Emit the compare insn and   return the rtx for register 0 in the proper mode.  */rtxgen_compare_reg (code, x, y)     enum rtx_code code;     rtx x, y;{  enum machine_mode mode = SELECT_CC_MODE (code, x, y);

⌨️ 快捷键说明

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