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

📄 a29k.c

📁 gcc编译工具没有什么特别
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Subroutines used for code generation on AMD Am29000.   Copyright (C) 1987, 88, 90-94, 1995, 1997, 1999 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 <stdio.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 "recog.h"#include "expr.h"#include "obstack.h"#include "tree.h"#include "reload.h"#define min(A,B)	((A) < (B) ? (A) : (B))/* This gives the size in words of the register stack for the current   procedure.  */static int a29k_regstack_size;/* True if the current procedure has a call instruction.  */static int a29k_makes_calls;/* This points to the last insn of the insn prologue.  It is set when   an insn without a filled delay slot is found near the start of the   function.  */static char *a29k_last_prologue_insn;/* This points to the first insn that will be in the epilogue.  It is null if   no epilogue is required.  */static char *a29k_first_epilogue_insn;/* This is nonzero if a a29k_first_epilogue_insn was put in a delay slot.  It   indicates that an intermediate label needs to be written.  */static int a29k_first_epilogue_insn_used;/* Location to hold the name of the current function.  We need this prolog to   contain the tag words prior to the declaration.  So the name must be stored   away.  */char *a29k_function_name;/* Mapping of registers to debug register numbers.  The only change is   for the frame pointer and the register numbers used for the incoming   arguments.  */int a29k_debug_reg_map[FIRST_PSEUDO_REGISTER];/* Save information from a "cmpxx" operation until the branch or scc is   emitted.  */rtx a29k_compare_op0, a29k_compare_op1;int a29k_compare_fp_p;/* Gives names for registers.  */extern char *reg_names[];/* Returns 1 if OP is a 8-bit constant. */intcint_8_operand (op, mode)     register rtx op;     enum machine_mode mode;{  return GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffffff00) == 0;}/* Returns 1 if OP is a 16-bit constant.  */intcint_16_operand (op, mode)     rtx op;     enum machine_mode mode;{  return GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff0000) == 0;}/* Returns 1 if OP is a constant that cannot be moved in a single insn.  */intlong_const_operand (op, mode)     register rtx op;     enum machine_mode mode;{  if (! CONSTANT_P (op))    return 0;  if (TARGET_29050 && GET_CODE (op) == CONST_INT      && (INTVAL (op) & 0xffff) == 0)    return 0;  return (GET_CODE (op) != CONST_INT	  || ((INTVAL (op) & 0xffff0000) != 0	      && (INTVAL (op) & 0xffff0000) != 0xffff0000	      && INTVAL (op) != 0x80000000));}/* The following four functions detect constants of 0, 8, 16, and 24 used as   a position in ZERO_EXTRACT operations.  They can either be the appropriate   constant integer or a shift (which will be produced by combine).  */static intshift_constant_operand (op, mode, val)     rtx op;     enum machine_mode mode;     int val;{  return ((GET_CODE (op) == CONST_INT && INTVAL (op) == val)	  || (GET_CODE (op) == ASHIFT	      && GET_CODE (XEXP (op, 0)) == CONST_INT	      && INTVAL (XEXP (op, 0)) == val / 8	      && GET_CODE (XEXP (op, 1)) == CONST_INT	      && INTVAL (XEXP (op, 1)) == 3));}intconst_0_operand (op, mode)     rtx op;     enum machine_mode mode;{  return shift_constant_operand (op, mode, 0);}intconst_8_operand (op, mode)     rtx op;     enum machine_mode mode;{  return shift_constant_operand (op, mode, 8);}intconst_16_operand (op, mode)     rtx op;     enum machine_mode mode;{  return shift_constant_operand (op, mode, 16);}intconst_24_operand (op, mode)     rtx op;     enum machine_mode mode;{  return shift_constant_operand (op, mode, 24);}/* Returns 1 if OP is a floating-point constant of the proper mode.  */intfloat_const_operand (op, mode)     rtx op;     enum machine_mode mode;{  return GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == mode;}/* Returns 1 if OP is a floating-point constant of the proper mode or a   general-purpose register.  */intgpc_reg_or_float_constant_operand (op, mode)     rtx op;     enum machine_mode mode;{  return float_const_operand (op, mode) || gpc_reg_operand (op, mode);}/* Returns 1 if OP is an integer constant of the proper mode or a   general-purpose register.  */intgpc_reg_or_integer_constant_operand (op, mode)     rtx op;     enum machine_mode mode;{  return ((GET_MODE (op) == VOIDmode	   && (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE))	  || gpc_reg_operand (op, mode));}     /* Returns 1 if OP is a special machine register.  */intspec_reg_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) != REG || GET_MODE (op) != mode)    return 0;  switch (GET_MODE_CLASS (mode))    {    case MODE_PARTIAL_INT:      return REGNO (op) >= R_BP && REGNO (op) <= R_CR;    case MODE_INT:      return REGNO (op) >= R_Q && REGNO (op) <= R_EXO;    default:      return 0;    }}/* Returns 1 if OP is an accumulator register.  */intaccum_reg_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (GET_CODE (op) == REG	  && REGNO (op) >= R_ACU (0) && REGNO (op) <= R_ACU (3));}/* Returns 1 if OP is a normal data register.  */intgpc_reg_operand (op, mode)     rtx op;     enum machine_mode mode;{  int regno;  if (GET_MODE (op) != mode && mode != VOIDmode)    return 0;  if (GET_CODE (op) == REG)    regno = REGNO (op);  else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)    {      regno = REGNO (SUBREG_REG (op));      if (regno < FIRST_PSEUDO_REGISTER)	regno += SUBREG_WORD (op);    }  else    return 0;  return (regno >= FIRST_PSEUDO_REGISTER || regno < R_BP	  || (regno >= R_KR (0) && regno <= R_KR (31)));}/* Returns 1 if OP is either an 8-bit constant integer or a general register.   If a register, it must be in the proper mode unless MODE is VOIDmode.  */intsrcb_operand (op, mode)      register rtx op;      enum machine_mode mode;{  if (GET_CODE (op) == CONST_INT      && (mode == QImode	  || (INTVAL (op) & 0xffffff00) == 0))    return 1;  if (GET_MODE (op) != mode && mode != VOIDmode)    return 0;  return gpc_reg_operand (op, mode);}intcmplsrcb_operand (op, mode)      register rtx op;      enum machine_mode mode;{  if (GET_CODE (op) == CONST_INT      && (mode == QImode	  || (INTVAL (op) & 0xffffff00) == 0xffffff00))    return 1;  if (GET_MODE (op) != mode && mode != VOIDmode)    return 0;  return gpc_reg_operand (op, mode);}/* Return 1 if OP is either an immediate or a general register.  This is used   for the input operand of mtsr/mtrsim.  */intgpc_reg_or_immediate_operand (op, mode)     rtx op;     enum machine_mode mode;{  return gpc_reg_operand (op, mode) || immediate_operand (op, mode);}/* Return 1 if OP can be used as the second operand of and AND insn.  This   includes srcb_operand and a constant whose complement fits in 8 bits.  */intand_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (srcb_operand (op, mode)	  || (GET_CODE (op) == CONST_INT	      && ((unsigned) ((~ INTVAL (op)) & GET_MODE_MASK (mode)) < 256)));}/* Return 1 if OP can be used as the second operand of an ADD insn.   This is the same as above, except we use negative, rather than   complement.   */intadd_operand (op, mode)     rtx op;     enum machine_mode mode;{  return (srcb_operand (op, mode)	  || (GET_CODE (op) == CONST_INT	      && ((unsigned) ((- INTVAL (op)) & GET_MODE_MASK (mode)) < 256)));}/* Return 1 if OP is a valid address in a CALL_INSN.  These are a SYMBOL_REF   to the current function, all SYMBOL_REFs if TARGET_SMALL_MEMORY, or   a sufficiently-small constant.  */intcall_operand (op, mode)     rtx op;     enum machine_mode mode;{  switch (GET_CODE (op))    {    case SYMBOL_REF:      return (TARGET_SMALL_MEMORY	      || (! TARGET_LARGE_MEMORY		  && ((GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_FLAG (op))		      || ! strcmp (XSTR (op, 0), current_function_name))));    case CONST_INT:      return (unsigned HOST_WIDE_INT) INTVAL (op) < 0x40000;    default:      return 0;    }}/* Return 1 if OP can be used as the input operand for a move insn.  */intin_operand (op, mode)     rtx op;     enum machine_mode mode;{  rtx orig_op = op;  if (! general_operand (op, mode))    return 0;  while (GET_CODE (op) == SUBREG)    op = SUBREG_REG (op);  switch (GET_CODE (op))    {    case REG:      return 1;    case MEM:      return (GET_MODE_SIZE (mode) >= UNITS_PER_WORD || TARGET_DW_ENABLE);    case CONST_INT:      if (GET_MODE_CLASS (mode) != MODE_INT	  && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)	return 0;      return 1;    case CONST:    case SYMBOL_REF:    case LABEL_REF:      return (GET_MODE (op) == mode	      || mode == SImode || mode == HImode || mode == QImode);    case CONST_DOUBLE:      return ((GET_MODE_CLASS (mode) == MODE_FLOAT	       && mode == GET_MODE (op))	      || (GET_MODE (op) == VOIDmode		  && GET_MODE_CLASS (mode) == MODE_INT));    default:      return 0;    }}/* Return 1 if OP can be used as the output operand for a move insn.  */intout_operand (op, mode)     rtx op;     enum machine_mode mode;{  rtx orig_op = op;  if (! general_operand (op, mode))    return 0;  while (GET_CODE (op) == SUBREG)    op = SUBREG_REG (op);  if (GET_CODE (op) == REG)    return (gpc_reg_operand (orig_op, mode)	    || spec_reg_operand (orig_op, mode)	    || (GET_MODE_CLASS (mode) == MODE_FLOAT		&& accum_reg_operand (orig_op, mode)));  else if (GET_CODE (op) == MEM)    return (GET_MODE_SIZE (mode) >= UNITS_PER_WORD || TARGET_DW_ENABLE);  else    return 0;}/* Return 1 if OP is an item in memory, given that we are in reload.  */intreload_memory_operand (op, mode)     rtx op;     enum machine_mode mode;{  int regno = true_regnum (op);  return (! CONSTANT_P (op)	  && (regno == -1	      || (GET_CODE (op) == REG		  && REGNO (op) >= FIRST_PSEUDO_REGISTER)));}/* Given an object for which reload_memory_operand is true, return the address   of the operand, taking into account anything that reload may do.  */rtxa29k_get_reloaded_address (op)     rtx op;{  if (GET_CODE (op) == SUBREG)    {      if (SUBREG_WORD (op) != 0)	abort ();      op = SUBREG_REG (op);    }  if (GET_CODE (op) == REG)    op = reg_equiv_mem[REGNO (op)];  return find_replacement (&XEXP (op, 0));}/* Subfunction of the following function.  Update the flags of any MEM   found in part of X.  */static voida29k_set_memflags_1 (x, in_struct_p, scalar_p, volatile_p, unchanging_p)     rtx x;     int in_struct_p, scalar_p, volatile_p, unchanging_p;{  int i;  switch (GET_CODE (x))    {    case SEQUENCE:    case PARALLEL:      for (i = XVECLEN (x, 0) - 1; i >= 0; i--)	a29k_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, volatile_p,			     unchanging_p);      break;    case INSN:      a29k_set_memflags_1 (PATTERN (x), in_struct_p, volatile_p,			   unchanging_p);      break;    case SET:      a29k_set_memflags_1 (SET_DEST (x), in_struct_p, volatile_p,			   unchanging_p);      a29k_set_memflags_1 (SET_SRC (x), in_struct_p, volatile_p, unchanging_p);      break;    case MEM:      MEM_IN_STRUCT_P (x) = in_struct_p;      MEM_SCALAR_P (x) = scalar_p;      MEM_VOLATILE_P (x) = volatile_p;      RTX_UNCHANGING_P (x) = unchanging_p;

⌨️ 快捷键说明

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