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

📄 d30v.c

📁 linux下的gcc编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Definitions of target machine for Mitsubishi D30V.   Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.   Contributed by Cygnus Solutions.   This file is part of GNU CC.   GNU CC is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the 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 of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   You should have received a copy of the GNU General Public License   along with GNU CC; see the file COPYING.  If not, write to   the 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 "expr.h"#include "obstack.h"#include "tm_p.h"#include "except.h"#include "function.h"#include "toplev.h"#include "integrate.h"#include "ggc.h"#include "target.h"#include "target-def.h"#include "langhooks.h"static void d30v_print_operand_memory_reference PARAMS ((FILE *, rtx));static void d30v_build_long_insn PARAMS ((HOST_WIDE_INT, HOST_WIDE_INT,					  rtx, rtx));static struct machine_function * d30v_init_machine_status PARAMS ((void));static void d30v_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void d30v_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));static int d30v_adjust_cost PARAMS ((rtx, rtx, rtx, int));static int d30v_issue_rate PARAMS ((void));/* Define the information needed to generate branch and scc insns.  This is   stored from the compare operation.  */struct rtx_def *d30v_compare_op0;struct rtx_def *d30v_compare_op1;/* Cached value of d30v_stack_info */static d30v_stack_t *d30v_stack_cache = (d30v_stack_t *)0;/* Values of the -mbranch-cost=n string.  */int d30v_branch_cost = D30V_DEFAULT_BRANCH_COST;const char *d30v_branch_cost_string = (const char *)0;/* Values of the -mcond-exec=n string.  */int d30v_cond_exec = D30V_DEFAULT_MAX_CONDITIONAL_EXECUTE;const char *d30v_cond_exec_string = (const char *)0;/* Whether or not a hard register can accept a register */unsigned char hard_regno_mode_ok[ (int)MAX_MACHINE_MODE ][FIRST_PSEUDO_REGISTER];/* Whether to try and avoid moves between two different modes */unsigned char modes_tieable_p[ (NUM_MACHINE_MODES) * (NUM_MACHINE_MODES) ];/* Map register number to smallest register class.  */enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];/* Map class letter into register class */enum reg_class reg_class_from_letter[256];/* 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 d30v_output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE d30v_output_function_epilogue#undef TARGET_SCHED_ADJUST_COST#define TARGET_SCHED_ADJUST_COST d30v_adjust_cost#undef TARGET_SCHED_ISSUE_RATE#define TARGET_SCHED_ISSUE_RATE d30v_issue_ratestruct gcc_target targetm = TARGET_INITIALIZER;/* Sometimes certain combinations of command options do not make   sense on a particular target machine.  You can define a macro   `OVERRIDE_OPTIONS' to take account of this.  This macro, if   defined, is executed once just after all the command options have   been parsed.   Don't use this macro to turn on various extra optimizations for   `-O'.  That is what `OPTIMIZATION_OPTIONS' is for.  */voidoverride_options (){  int regno, i, ok_p;  enum machine_mode mode1, mode2;  /* Set up the branch cost information */  if (d30v_branch_cost_string)    d30v_branch_cost = atoi (d30v_branch_cost_string);  /* Set up max # instructions to use with conditional execution */  if (d30v_cond_exec_string)    d30v_cond_exec = atoi (d30v_cond_exec_string);  /* Setup hard_regno_mode_ok/modes_tieable_p */  for (mode1 = VOIDmode;       (int)mode1 < NUM_MACHINE_MODES;       mode1 = (enum machine_mode)((int)mode1 + 1))    {      int size = GET_MODE_SIZE (mode1);      int large_p = size > UNITS_PER_WORD;      int int_p = GET_MODE_CLASS (mode1) == MODE_INT;      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)	{	  if (mode1 == VOIDmode)	    ok_p = FALSE;	  else if (GPR_P (regno))	    {	      if (!large_p)		ok_p = TRUE;	      else		ok_p = (((regno - GPR_FIRST) & 1) == 0);	    }	  else if (FLAG_P (regno))	    ok_p = (mode1 == CCmode);	  else if (CR_P (regno))	    ok_p = int_p && !large_p;	  else if (ACCUM_P (regno))	    ok_p = (mode1 == DImode);	  else if (SPECIAL_REG_P (regno))	    ok_p = (mode1 == SImode);	  else	    ok_p = FALSE;	  hard_regno_mode_ok[ (int)mode1 ][ regno ] = ok_p;	}      /* A C expression that is nonzero if it is desirable to choose	 register allocation so as to avoid move instructions between a	 value of mode MODE1 and a value of mode MODE2.	 If `HARD_REGNO_MODE_OK (R, MODE1)' and `HARD_REGNO_MODE_OK (R,	 MODE2)' are ever different for any R, then `MODES_TIEABLE_P (MODE1,	 MODE2)' must be zero. */      for (mode2 = VOIDmode;	   (int)mode2 <= NUM_MACHINE_MODES;	   mode2 = (enum machine_mode)((int)mode2 + 1))	{	  if (mode1 == mode2)	    ok_p = TRUE;#if 0	  else if (GET_MODE_CLASS (mode1) == MODE_INT		   && GET_MODE_SIZE (mode1) <= UNITS_PER_WORD		   && GET_MODE_CLASS (mode2) == MODE_INT		   && GET_MODE_SIZE (mode2) <= UNITS_PER_WORD)	    ok_p = TRUE;#endif	  else	    ok_p = FALSE;	  modes_tieable_p[ ((int)mode1 * (NUM_MACHINE_MODES)) + (int)mode2 ] = ok_p;	}    }#if 0  for (mode1 = VOIDmode;       (int)mode1 < NUM_MACHINE_MODES;       mode1 = (enum machine_mode)((int)mode1 + 1))    {      for (mode2 = VOIDmode;	   (int)mode2 <= NUM_MACHINE_MODES;	   mode2 = (enum machine_mode)((int)mode2 + 1))	{	  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)	    if (ok_p		&& (hard_regno_mode_ok[(int)mode1][regno]		    != hard_regno_mode_ok[(int)mode2][regno]))	      error ("bad modes_tieable_p for register %s, mode1 %s, mode2 %s",		     reg_names[regno], GET_MODE_NAME (mode1),		     GET_MODE_NAME (mode2));	}    }#endif  /* A C expression whose value is a register class containing hard     register REGNO.  In general there is more than one such class;     choose a class which is "minimal", meaning that no smaller class     also contains the register. */  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)    {      enum reg_class class;      if (GPR_P (regno))	class = (IN_RANGE_P (regno, GPR_FIRST+2, GPR_FIRST+62)		 && ((regno - GPR_FIRST) & 1) == 0) ? EVEN_REGS : GPR_REGS;      else if (regno == FLAG_F0)	class = F0_REGS;      else if (regno == FLAG_F1)	class = F1_REGS;      else if (FLAG_P (regno))	class = OTHER_FLAG_REGS;      else if (ACCUM_P (regno))	class = ACCUM_REGS;      else if (regno == CR_RPT_C)	class = REPEAT_REGS;      else if (CR_P (regno))	class = CR_REGS;      else if (SPECIAL_REG_P (regno))	class = GPR_REGS;      else	class = NO_REGS;      regno_reg_class[regno] = class;#if 0      {	static const char *const names[] = REG_CLASS_NAMES;	fprintf (stderr, "Register %s class is %s, can hold modes", reg_names[regno], names[class]);	for (mode1 = VOIDmode;	     (int)mode1 < NUM_MACHINE_MODES;	     mode1 = (enum machine_mode)((int)mode1 + 1))	  {	    if (hard_regno_mode_ok[ (int)mode1 ][ regno ])	      fprintf (stderr, " %s", GET_MODE_NAME (mode1));	  }	fprintf (stderr, "\n");      }#endif    }  /* A C expression which defines the machine-dependent operand     constraint letters for register classes.  If CHAR is such a     letter, the value should be the register class corresponding to     it.  Otherwise, the value should be `NO_REGS'.  The register     letter `r', corresponding to class `GENERAL_REGS', will not be     passed to this macro; you do not need to handle it.     The following letters are unavailable, due to being used as     constraints:	'0'..'9'	'<', '>'	'E', 'F', 'G', 'H'	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P'	'Q', 'R', 'S', 'T', 'U'	'V', 'X'	'g', 'i', 'm', 'n', 'o', 'p', 'r', 's' */  for (i = 0; i < 256; i++)    reg_class_from_letter[i] = NO_REGS;  reg_class_from_letter['a'] = ACCUM_REGS;  reg_class_from_letter['b'] = BR_FLAG_REGS;  reg_class_from_letter['c'] = CR_REGS;  reg_class_from_letter['d'] = GPR_REGS;  reg_class_from_letter['e'] = EVEN_REGS;  reg_class_from_letter['f'] = FLAG_REGS;  reg_class_from_letter['l'] = REPEAT_REGS;  reg_class_from_letter['x'] = F0_REGS;  reg_class_from_letter['y'] = F1_REGS;  reg_class_from_letter['z'] = OTHER_FLAG_REGS;}/* Return true if a memory operand is a short memory operand.  */intshort_memory_operand (op, mode)     register rtx op;     enum machine_mode mode;{  if (GET_CODE (op) != MEM)    return FALSE;  if (GET_MODE (op) != mode && mode != VOIDmode)    return FALSE;  return (d30v_legitimate_address_p (mode, XEXP (op, 0), reload_completed)	  == 1);}/* Return true if a memory operand is a long operand.  */intlong_memory_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) != MEM)    return FALSE;  if (GET_MODE (op) != mode && mode != VOIDmode)    return FALSE;  return (d30v_legitimate_address_p (mode, XEXP (op, 0), reload_completed)	  == 2);}/* Return true if a memory operand is valid for the D30V.  */intd30v_memory_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) != MEM)    return FALSE;  if (GET_MODE (op) != mode && mode != VOIDmode)    return FALSE;  return (d30v_legitimate_address_p (mode, XEXP (op, 0), reload_completed)	  != 0);}/* Return true if a memory operand uses a single register for the   address.  */intsingle_reg_memory_operand (op, mode)     rtx op;     enum machine_mode mode;{  rtx addr;  if (GET_CODE (op) != MEM)    return FALSE;  if (GET_MODE (op) != mode && mode != VOIDmode)    return FALSE;  addr = XEXP (op, 0);  if (! d30v_legitimate_address_p (mode, addr, reload_completed))    return FALSE;  if (GET_CODE (addr) == SUBREG)    addr = SUBREG_REG (addr);  return (GET_CODE (addr) == REG);}/* Return true if a memory operand uses a constant address.  */intconst_addr_memory_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) != MEM)    return FALSE;  if (GET_MODE (op) != mode && mode != VOIDmode)    return FALSE;  if (! d30v_legitimate_address_p (mode, XEXP (op, 0), reload_completed))    return FALSE;  switch (GET_CODE (XEXP (op, 0)))    {    default:      break;    case SYMBOL_REF:    case LABEL_REF:    case CONST_INT:    case CONST:      return TRUE;    }  return FALSE;}/* Return true if operand is a memory reference suitable for a call.  */intcall_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) != MEM)    return FALSE;  if (GET_MODE (op) != mode && mode != VOIDmode)    return FALSE;  if (! d30v_legitimate_address_p (mode, XEXP (op, 0), reload_completed))    return FALSE;  switch (GET_CODE (XEXP (op, 0)))    {    default:      break;    case SUBREG:      op = SUBREG_REG (op);      if (GET_CODE (op) != REG)	return FALSE;      /* fall through */    case REG:      return (GPR_OR_PSEUDO_P (REGNO (XEXP (op, 0))));    case SYMBOL_REF:    case LABEL_REF:    case CONST_INT:    case CONST:      return TRUE;    }  return FALSE;}/* Return true if operand is a GPR register.  */intgpr_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_MODE (op) != mode && mode != VOIDmode)    return FALSE;  if (GET_CODE (op) == SUBREG)    {      if (GET_CODE (SUBREG_REG (op)) != REG)	return register_operand (op, mode);      op = SUBREG_REG (op);    }  if (GET_CODE (op) != REG)    return FALSE;  return GPR_OR_PSEUDO_P (REGNO (op));}/* Return true if operand is an accumulator register.  */intaccum_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_MODE (op) != mode && mode != VOIDmode)    return FALSE;  if (GET_CODE (op) == SUBREG)    {      if (GET_CODE (SUBREG_REG (op)) != REG)	return register_operand (op, mode);      op = SUBREG_REG (op);    }  if (GET_CODE (op) != REG)    return FALSE;  return ACCUM_OR_PSEUDO_P (REGNO (op));}/* Return true if operand is a GPR or an accumulator register.  */intgpr_or_accum_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_MODE (op) != mode && mode != VOIDmode)    return FALSE;  if (GET_CODE (op) == SUBREG)    {      if (GET_CODE (SUBREG_REG (op)) != REG)	return register_operand (op, mode);      op = SUBREG_REG (op);

⌨️ 快捷键说明

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