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

📄 a29k.c

📁 gcc3.2.1源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Subroutines used for code generation on AMD Am29000.   Copyright (C) 1987, 1988, 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1998,   1999, 2000 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 "tree.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 "function.h"#include "expr.h"#include "obstack.h"#include "reload.h"#include "tm_p.h"#include "target.h"#include "target-def.h"static int shift_constant_operand PARAMS ((rtx, enum machine_mode, int));static void a29k_set_memflags_1 PARAMS ((rtx, int, int, int, int));static void compute_regstack_size PARAMS ((void));static void check_epilogue_internal_label PARAMS ((FILE *));static void output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));static void a29k_asm_named_section PARAMS ((const char *, unsigned int));static int a29k_adjust_cost PARAMS ((rtx, rtx, rtx, int));#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.  */const 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;/* Initialize the GCC target structure.  */#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"#undef TARGET_ASM_ALIGNED_SI_OP#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE output_function_epilogue#undef TARGET_SCHED_ADJUST_COST#define TARGET_SCHED_ADJUST_COST a29k_adjust_coststruct gcc_target targetm = TARGET_INITIALIZER;/* Returns 1 if OP is a 8-bit constant.  */intcint_8_operand (op, mode)     register rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  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 ATTRIBUTE_UNUSED;{  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 ATTRIBUTE_UNUSED;{  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 ATTRIBUTE_UNUSED;     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 ATTRIBUTE_UNUSED;{  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)    {      if (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)	regno = subreg_regno (op);      else	regno = REGNO (SUBREG_REG (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 ATTRIBUTE_UNUSED;{  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;{  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 ATTRIBUTE_UNUSED;{  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_BYTE (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, scalar_p,			     volatile_p, unchanging_p);      break;    case INSN:      a29k_set_memflags_1 (PATTERN (x), in_struct_p, scalar_p, volatile_p,			   unchanging_p);      break;    case SET:      a29k_set_memflags_1 (SET_DEST (x), in_struct_p, scalar_p, volatile_p,			   unchanging_p);      a29k_set_memflags_1 (SET_SRC (x), in_struct_p, scalar_p, volatile_p,			   unchanging_p);      break;    case MEM:      MEM_IN_STRUCT_P (x) = in_struct_p;

⌨️ 快捷键说明

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