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

📄 romp.c

📁 linux下的gcc编译器
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Subroutines used for code generation on ROMP.   Copyright (C) 1990, 1991, 1992, 1993, 1997, 1998, 1999, 2000, 2002   Free Software Foundation, Inc.   Contributed by Richard Kenner (kenner@nyu.edu)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 "system.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "output.h"#include "insn-attr.h"#include "flags.h"#include "recog.h"#include "obstack.h"#include "tree.h"#include "function.h"#include "expr.h"#include "ggc.h"#include "toplev.h"#include "tm_p.h"#include "target.h"#include "target-def.h"#define min(A,B)	((A) < (B) ? (A) : (B))#define max(A,B)	((A) > (B) ? (A) : (B))static int unsigned_comparisons_p PARAMS ((rtx));static void output_loadsave_fpregs PARAMS ((FILE *, enum rtx_code, rtx));static void output_fpops PARAMS ((FILE *));static void init_fpops PARAMS ((void));static int memory_offset_in_range_p PARAMS ((rtx, enum machine_mode, int, int));static unsigned int hash_rtx PARAMS ((rtx));static void romp_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void romp_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));static void romp_select_rtx_section PARAMS ((enum machine_mode, rtx,					     unsigned HOST_WIDE_INT));static void romp_encode_section_info PARAMS ((tree, int));/* Initialize the GCC target structure.  */#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE romp_output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE romp_output_function_epilogue#undef TARGET_ASM_SELECT_RTX_SECTION#define TARGET_ASM_SELECT_RTX_SECTION romp_select_rtx_section#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO romp_encode_section_infostruct gcc_target targetm = TARGET_INITIALIZER;/* Return 1 if the insn using CC0 set by INSN does not contain   any unsigned tests applied to the condition codes.   Based on `next_insn_tests_no_inequality' in recog.c.  */intnext_insn_tests_no_unsigned (insn)     rtx insn;{  register rtx next = next_cc0_user (insn);  if (next == 0)    {      if (find_reg_note (insn, REG_UNUSED, cc0_rtx))	return 1;      else	abort ();    }  return ((GET_CODE (next) == JUMP_INSN	   || GET_CODE (next) == INSN	   || GET_CODE (next) == CALL_INSN)	  && ! unsigned_comparisons_p (PATTERN (next)));}static intunsigned_comparisons_p (x)     rtx x;{  register const char *fmt;  register int len, i;  register enum rtx_code code = GET_CODE (x);  switch (code)    {    case REG:    case PC:    case CC0:    case CONST_INT:    case CONST_DOUBLE:    case CONST:    case LABEL_REF:    case SYMBOL_REF:      return 0;    case LTU:    case GTU:    case LEU:    case GEU:      return (XEXP (x, 0) == cc0_rtx || XEXP (x, 1) == cc0_rtx);    default:      break;    }  len = GET_RTX_LENGTH (code);  fmt = GET_RTX_FORMAT (code);  for (i = 0; i < len; i++)    {      if (fmt[i] == 'e')	{	  if (unsigned_comparisons_p (XEXP (x, i)))	    return 1;	}      else if (fmt[i] == 'E')	{	  register int j;	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)	    if (unsigned_comparisons_p (XVECEXP (x, i, j)))	      return 1;	}    }	      return 0;}/* Update the condition code from the insn.  Look mostly at the first   byte of the machine-specific insn description information.   cc_state.value[12] refer to two possible values that might correspond   to the CC.  We only store register values.  */voidupdate_cc (body, insn)    rtx body ATTRIBUTE_UNUSED;    rtx insn;{  switch (get_attr_cc (insn))    {    case CC_NONE:      /* Insn does not affect the CC at all.  */      break;    case CC_CHANGE0:      /* Insn doesn't affect the CC but does modify operand[0], known to be	 a register.  */      if (cc_status.value1 != 0	  && reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value1))	cc_status.value1 = 0;      if (cc_status.value2 != 0	  && reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value2))	cc_status.value2 = 0;      break;    case CC_COPY1TO0:      /* Insn copies operand[1] to operand[0], both registers, but doesn't         affect the CC.  */      if (cc_status.value1 != 0	  && reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value1))	cc_status.value1 = 0;      if (cc_status.value2 != 0	  && reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value2))	cc_status.value2 = 0;      if (cc_status.value1 != 0	  && rtx_equal_p (cc_status.value1, recog_data.operand[1]))	cc_status.value2 = recog_data.operand[0];      if (cc_status.value2 != 0	  && rtx_equal_p (cc_status.value2, recog_data.operand[1]))	cc_status.value1 = recog_data.operand[0];      break;    case CC_CLOBBER:      /* Insn clobbers CC.  */      CC_STATUS_INIT;      break;    case CC_SETS:      /* Insn sets CC to recog_data.operand[0], but overflow is impossible.  */      CC_STATUS_INIT;      cc_status.flags |= CC_NO_OVERFLOW;      cc_status.value1 = recog_data.operand[0];      break;   case CC_COMPARE:      /* Insn is a compare which sets the CC fully.  Update CC_STATUS for this	 compare and mark whether the test will be signed or unsigned.  */      {	register rtx p = PATTERN (insn);	CC_STATUS_INIT;	if (GET_CODE (p) == PARALLEL)	  p = XVECEXP (p, 0, 0);	cc_status.value1 = SET_SRC (p);	if (GET_CODE (SET_SRC (p)) == REG)	  cc_status.flags |= CC_NO_OVERFLOW;	if (! next_insn_tests_no_unsigned (insn))	  cc_status.flags |= CC_UNSIGNED;      }      break;    case CC_TBIT:      /* Insn sets T bit if result is nonzero.  Next insn must be branch.  */      CC_STATUS_INIT;      cc_status.flags = CC_IN_TB | CC_NOT_NEGATIVE;      break;    default:      abort ();   }}/* Return 1 if a previous compare needs to be re-issued.  This will happen   if two compares tested the same objects, but one was signed and the   other unsigned.  OP is the comparison operation being performed.  */intrestore_compare_p (op)     rtx op;{  enum rtx_code code = GET_CODE (op);  return (((code == GEU || code == LEU || code == GTU || code == LTU)	   && ! (cc_status.flags & CC_UNSIGNED))	  || ((code == GE || code == LE || code == GT || code == LT)	      && (cc_status.flags & CC_UNSIGNED)));}/*  Generate the (long) string corresponding to an inline multiply insn.    Note that `r10' does not refer to the register r10, but rather to the    SCR used as the MQ.  */const char *output_in_line_mul (){  static char insns[200];  int i;  strcpy (insns, "s %0,%0\n");  strcat (insns, "\tmts r10,%1\n");  for (i = 0; i < 16; i++)    strcat (insns, "\tm %0,%2\n");  strcat (insns, "\tmfs r10,%0");  return insns;}/* Returns 1 if OP is a memory reference with an offset from a register within   the range specified.  The offset must also be a multiple of the size of the   mode.  */static intmemory_offset_in_range_p (op, mode, low, high)     register rtx op;     enum machine_mode mode;     int low, high;{  int offset = 0;  if (! memory_operand (op, mode))    return 0;  while (GET_CODE (op) == SUBREG)    {      offset += SUBREG_BYTE (op);      op = SUBREG_REG (op);    }  /* We must now have either (mem (reg (x)), (mem (plus (reg (x)) (c))),     or a constant pool address.  */  if (GET_CODE (op) != MEM)    abort ();  /* Now use the actual mode and get the address.  */  mode = GET_MODE (op);  op = XEXP (op, 0);  if (GET_CODE (op) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (op))    offset = get_pool_offset (op) + 12;  else if (GET_CODE (op) == PLUS)    {      if (GET_CODE (XEXP (op, 1)) != CONST_INT	  || ! register_operand (XEXP (op, 0), Pmode))	return 0;      offset += INTVAL (XEXP (op, 1));    }  else if (! register_operand (op, Pmode))    return 0;  return (offset >= low && offset <= high	  && (offset % GET_MODE_SIZE (mode) == 0));}/* Return 1 if OP is a valid operand for a memory reference insn that can   only reference indirect through a register.   */intzero_memory_operand (op, mode)     rtx op;     enum machine_mode mode;{  return memory_offset_in_range_p (op, mode, 0, 0);}/* Return 1 if OP is a valid operand for a `short' memory reference insn.  */intshort_memory_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (mode == VOIDmode)    mode = GET_MODE (op);  return memory_offset_in_range_p (op, mode, 0,				   15 * min (UNITS_PER_WORD,					     GET_MODE_SIZE (mode)));}/* Returns 1 if OP is a memory reference involving a symbolic constant   that is not in the constant pool.  */intsymbolic_memory_operand (op, mode)     register rtx op;     enum machine_mode mode;{  if (! memory_operand (op, mode))    return 0;  while (GET_CODE (op) == SUBREG)    op = SUBREG_REG (op);  if (GET_CODE (op) != MEM)    abort ();  op = XEXP (op, 0);  if (constant_pool_address_operand (op, VOIDmode))    return 0;  else    return romp_symbolic_operand (op, Pmode)      || (GET_CODE (op) == PLUS && register_operand (XEXP (op, 0), Pmode)	  && romp_symbolic_operand (XEXP (op, 1), Pmode));}/* Returns 1 if OP is a constant pool reference to the current function.  */intcurrent_function_operand (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  if (GET_CODE (op) != MEM || GET_CODE (XEXP (op, 0)) != SYMBOL_REF      ||  ! CONSTANT_POOL_ADDRESS_P (XEXP (op, 0)))    return 0;  op = get_pool_constant (XEXP (op, 0));  return (GET_CODE (op) == SYMBOL_REF	  && ! strcmp (current_function_name, XSTR (op, 0)));}/* Return nonzero if this function is known to have a null epilogue.  */intnull_epilogue (){  return (reload_completed	  && first_reg_to_save () == 16	  && ! romp_pushes_stack ());}/* Returns 1 if OP is the address of a location in the constant pool.  */intconstant_pool_address_operand (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  return ((GET_CODE (op) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (op))	  || (GET_CODE (op) == CONST && GET_CODE (XEXP (op, 0)) == PLUS	      && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT	      && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF	      && CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (op, 0), 0))));}/* Returns 1 if OP is either a symbol reference or a sum of a symbol   reference and a constant.  */intromp_symbolic_operand (op, mode)     register rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  switch (GET_CODE (op))    {    case SYMBOL_REF:    case LABEL_REF:      return ! op->integrated;    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;    default:      return 0;    }}/* Returns 1 if OP is a valid constant for the ROMP.  */intconstant_operand (op, mode)    register rtx op;    enum machine_mode mode;{  switch (GET_CODE (op))    {    case LABEL_REF:    case SYMBOL_REF:    case PLUS:    case CONST:      return romp_symbolic_operand (op,mode);    case CONST_INT:      return (unsigned int) (INTVAL (op) + 0x8000) < 0x10000	     || (INTVAL (op) & 0xffff) == 0 || (INTVAL (op) & 0xffff0000) == 0;    default:      return 0;    }}/* Returns 1 if OP is either a constant integer valid for the ROMP or a   register.  If a register, it must be in the proper mode unless MODE is   VOIDmode.  */intreg_or_cint_operand (op, mode)      register rtx op;      enum machine_mode mode;{  if (GET_CODE (op) == CONST_INT)    return constant_operand (op, mode);  return register_operand (op, mode);}/* Return 1 is the operand is either a register or ANY constant integer.  */intreg_or_any_cint_operand (op, mode)    register rtx op;    enum machine_mode mode;{     return GET_CODE (op) == CONST_INT || register_operand (op, mode);}/* Return 1 if the operand is either a register or a valid D-type operand.  */intreg_or_D_operand (op, mode)    register rtx op;    enum machine_mode mode;{  if (GET_CODE (op) == CONST_INT)    return (unsigned) (INTVAL (op) + 0x8000) < 0x10000;  return register_operand (op, mode);}/* Return 1 if the operand is either a register or an item that can be   used as the operand of an SI add insn.  */intreg_or_add_operand (op, mode)    register rtx op;    enum machine_mode mode;{  return reg_or_D_operand (op, mode) || romp_symbolic_operand (op, mode)	 || (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0);}/* Return 1 if the operand is either a register or an item that can be   used as the operand of a ROMP logical AND insn.  */intreg_or_and_operand (op, mode)    register rtx op;    enum machine_mode mode;{  if (reg_or_cint_operand (op, mode))    return 1;

⌨️ 快捷键说明

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