m32r.c

来自「gcc3.2.1源代码」· C语言 代码 · 共 2,386 行 · 第 1/5 页

C
2,386
字号
/* Subroutines used for code generation on the Mitsubishi M32R cpu.   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002   Free Software Foundation, Inc.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 "tree.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 "expr.h"#include "function.h"#include "recog.h"#include "toplev.h"#include "ggc.h"#include "m32r-protos.h"#include "target.h"#include "target-def.h"/* Save the operands last given to a compare for use when we   generate a scc or bcc insn.  */rtx m32r_compare_op0, m32r_compare_op1;/* Array of valid operand punctuation characters.  */char m32r_punct_chars[256];/* Selected code model.  */const char * m32r_model_string = M32R_MODEL_DEFAULT;enum m32r_model m32r_model;/* Selected SDA support.  */const char * m32r_sdata_string = M32R_SDATA_DEFAULT;enum m32r_sdata m32r_sdata;/* Scheduler support */static int m32r_sched_odd_word_p;/* Forward declaration.  */static void  init_reg_tables			PARAMS ((void));static void  block_move_call			PARAMS ((rtx, rtx, rtx));static int   m32r_is_insn			PARAMS ((rtx));const struct attribute_spec m32r_attribute_table[];static tree  m32r_handle_model_attribute PARAMS ((tree *, tree, tree, int, bool *));static void  m32r_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void  m32r_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));static int    m32r_adjust_cost 	   PARAMS ((rtx, rtx, rtx, int));static int    m32r_adjust_priority PARAMS ((rtx, int));static void   m32r_sched_init	   PARAMS ((FILE *, int, int));static int    m32r_sched_reorder   PARAMS ((FILE *, int, rtx *, int *, int));static int    m32r_variable_issue  PARAMS ((FILE *, int, rtx, int));static int    m32r_issue_rate	   PARAMS ((void));/* Initialize the GCC target structure.  */#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE m32r_attribute_table#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 m32r_output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE m32r_output_function_epilogue#undef TARGET_SCHED_ADJUST_COST#define TARGET_SCHED_ADJUST_COST m32r_adjust_cost#undef TARGET_SCHED_ADJUST_PRIORITY#define TARGET_SCHED_ADJUST_PRIORITY m32r_adjust_priority#undef TARGET_SCHED_ISSUE_RATE#define TARGET_SCHED_ISSUE_RATE m32r_issue_rate#undef TARGET_SCHED_VARIABLE_ISSUE#define TARGET_SCHED_VARIABLE_ISSUE m32r_variable_issue#undef TARGET_SCHED_INIT#define TARGET_SCHED_INIT m32r_sched_init#undef TARGET_SCHED_REORDER#define TARGET_SCHED_REORDER m32r_sched_reorderstruct gcc_target targetm = TARGET_INITIALIZER;/* Called by OVERRIDE_OPTIONS to initialize various things.  */voidm32r_init (){  init_reg_tables ();  /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P.  */  memset (m32r_punct_chars, 0, sizeof (m32r_punct_chars));  m32r_punct_chars['#'] = 1;  m32r_punct_chars['@'] = 1; /* ??? no longer used */  /* Provide default value if not specified.  */  if (!g_switch_set)    g_switch_value = SDATA_DEFAULT_SIZE;  if (strcmp (m32r_model_string, "small") == 0)    m32r_model = M32R_MODEL_SMALL;  else if (strcmp (m32r_model_string, "medium") == 0)    m32r_model = M32R_MODEL_MEDIUM;  else if (strcmp (m32r_model_string, "large") == 0)    m32r_model = M32R_MODEL_LARGE;  else    error ("bad value (%s) for -mmodel switch", m32r_model_string);  if (strcmp (m32r_sdata_string, "none") == 0)    m32r_sdata = M32R_SDATA_NONE;  else if (strcmp (m32r_sdata_string, "sdata") == 0)    m32r_sdata = M32R_SDATA_SDATA;  else if (strcmp (m32r_sdata_string, "use") == 0)    m32r_sdata = M32R_SDATA_USE;  else    error ("bad value (%s) for -msdata switch", m32r_sdata_string);}/* Vectors to keep interesting information about registers where it can easily   be got.  We use to use the actual mode value as the bit number, but there   is (or may be) more than 32 modes now.  Instead we use two tables: one   indexed by hard register number, and one indexed by mode.  *//* The purpose of m32r_mode_class is to shrink the range of modes so that   they all fit (as bit numbers) in a 32 bit word (again).  Each real mode is   mapped into one m32r_mode_class mode.  */enum m32r_mode_class{  C_MODE,  S_MODE, D_MODE, T_MODE, O_MODE,  SF_MODE, DF_MODE, TF_MODE, OF_MODE, A_MODE};/* Modes for condition codes.  */#define C_MODES (1 << (int) C_MODE)/* Modes for single-word and smaller quantities.  */#define S_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE))/* Modes for double-word and smaller quantities.  */#define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << DF_MODE))/* Modes for quad-word and smaller quantities.  */#define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))/* Modes for accumulators.  */#define A_MODES (1 << (int) A_MODE)/* Value is 1 if register/mode pair is acceptable on arc.  */unsigned int m32r_hard_regno_mode_ok[FIRST_PSEUDO_REGISTER] ={  T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES,  T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, S_MODES, S_MODES, S_MODES,  S_MODES, C_MODES, A_MODES, A_MODES};unsigned int m32r_mode_class [NUM_MACHINE_MODES];enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER];static voidinit_reg_tables (){  int i;  for (i = 0; i < NUM_MACHINE_MODES; i++)    {      switch (GET_MODE_CLASS (i))	{	case MODE_INT:	case MODE_PARTIAL_INT:	case MODE_COMPLEX_INT:	  if (GET_MODE_SIZE (i) <= 4)	    m32r_mode_class[i] = 1 << (int) S_MODE;	  else if (GET_MODE_SIZE (i) == 8)	    m32r_mode_class[i] = 1 << (int) D_MODE;	  else if (GET_MODE_SIZE (i) == 16)	    m32r_mode_class[i] = 1 << (int) T_MODE;	  else if (GET_MODE_SIZE (i) == 32)	    m32r_mode_class[i] = 1 << (int) O_MODE;	  else 	    m32r_mode_class[i] = 0;	  break;	case MODE_FLOAT:	case MODE_COMPLEX_FLOAT:	  if (GET_MODE_SIZE (i) <= 4)	    m32r_mode_class[i] = 1 << (int) SF_MODE;	  else if (GET_MODE_SIZE (i) == 8)	    m32r_mode_class[i] = 1 << (int) DF_MODE;	  else if (GET_MODE_SIZE (i) == 16)	    m32r_mode_class[i] = 1 << (int) TF_MODE;	  else if (GET_MODE_SIZE (i) == 32)	    m32r_mode_class[i] = 1 << (int) OF_MODE;	  else 	    m32r_mode_class[i] = 0;	  break;	case MODE_CC:	default:	  /* mode_class hasn't been initialized yet for EXTRA_CC_MODES, so	     we must explicitly check for them here.  */	  if (i == (int) CCmode)	    m32r_mode_class[i] = 1 << (int) C_MODE;	  else	    m32r_mode_class[i] = 0;	  break;	}    }  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)    {      if (GPR_P (i))	m32r_regno_reg_class[i] = GENERAL_REGS;      else if (i == ARG_POINTER_REGNUM)	m32r_regno_reg_class[i] = GENERAL_REGS;      else	m32r_regno_reg_class[i] = NO_REGS;    }}/* M32R specific attribute support.   interrupt - for interrupt functions   model - select code model used to access object	small: addresses use 24 bits, use bl to make calls	medium: addresses use 32 bits, use bl to make calls	large: addresses use 32 bits, use seth/add3/jl to make calls	Grep for MODEL in m32r.h for more info.*/static tree small_ident1;static tree small_ident2;static tree medium_ident1;static tree medium_ident2;static tree large_ident1;static tree large_ident2;static voidinit_idents PARAMS ((void)){  if (small_ident1 == 0)    {      small_ident1 = get_identifier ("small");      small_ident2 = get_identifier ("__small__");      medium_ident1 = get_identifier ("medium");      medium_ident2 = get_identifier ("__medium__");      large_ident1 = get_identifier ("large");      large_ident2 = get_identifier ("__large__");    }}const struct attribute_spec m32r_attribute_table[] ={  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */  { "interrupt", 0, 0, true,  false, false, NULL },  { "model",     1, 1, true,  false, false, m32r_handle_model_attribute },  { NULL,        0, 0, false, false, false, NULL }};/* Handle an "model" attribute; arguments as in   struct attribute_spec.handler.  */static treem32r_handle_model_attribute (node, name, args, flags, no_add_attrs)     tree *node ATTRIBUTE_UNUSED;     tree name;     tree args;     int flags ATTRIBUTE_UNUSED;     bool *no_add_attrs;{  tree arg;  init_idents ();  arg = TREE_VALUE (args);  if (arg != small_ident1      && arg != small_ident2      && arg != medium_ident1      && arg != medium_ident2      && arg != large_ident1      && arg != large_ident2)    {      warning ("invalid argument of `%s' attribute",	       IDENTIFIER_POINTER (name));      *no_add_attrs = true;    }  return NULL_TREE;}/* A C statement or statements to switch to the appropriate   section for output of DECL.  DECL is either a `VAR_DECL' node   or a constant of some sort.  RELOC indicates whether forming   the initial value of DECL requires link-time relocations.  */voidm32r_select_section (decl, reloc)     tree decl;     int reloc;{  if (TREE_CODE (decl) == STRING_CST)    {      if (! flag_writable_strings)	const_section ();      else	data_section ();    }  else if (TREE_CODE (decl) == VAR_DECL)    {      if (SDATA_NAME_P (XSTR (XEXP (DECL_RTL (decl), 0), 0)))	sdata_section ();      else if ((flag_pic && reloc)	       || !TREE_READONLY (decl)	       || TREE_SIDE_EFFECTS (decl)	       || !DECL_INITIAL (decl)	       || (DECL_INITIAL (decl) != error_mark_node		   && !TREE_CONSTANT (DECL_INITIAL (decl))))	data_section ();      else	const_section ();    }  else    const_section ();}/* Encode section information of DECL, which is either a VAR_DECL,   FUNCTION_DECL, STRING_CST, CONSTRUCTOR, or ???.   For the M32R we want to record:   - whether the object lives in .sdata/.sbss.     objects living in .sdata/.sbss are prefixed with SDATA_FLAG_CHAR   - what code model should be used to access the object     small: recorded with no flag - for space efficiency since they'll            be the most common     medium: prefixed with MEDIUM_FLAG_CHAR     large: prefixed with LARGE_FLAG_CHAR*/voidm32r_encode_section_info (decl)     tree decl;{  char prefix = 0;  tree model = 0;  switch (TREE_CODE (decl))    {    case VAR_DECL :    case FUNCTION_DECL :      model = lookup_attribute ("model", DECL_ATTRIBUTES (decl));      break;    case STRING_CST :    case CONSTRUCTOR :      /* ??? document all others that can appear here */    default :      return;    }  /* Only mark the object as being small data area addressable if     it hasn't been explicitly marked with a code model.     The user can explicitly put an object in the small data area with the     section attribute.  If the object is in sdata/sbss and marked with a     code model do both [put the object in .sdata and mark it as being     addressed with a specific code model - don't mark it as being addressed     with an SDA reloc though].  This is ok and might be useful at times.  If     the object doesn't fit the linker will give an error.  */  if (! model)    {      if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd'	  && DECL_SECTION_NAME (decl) != NULL_TREE)	{	  char *name = (char *) TREE_STRING_POINTER (DECL_SECTION_NAME (decl));	  if (! strcmp (name, ".sdata") || ! strcmp (name, ".sbss"))	    {#if 0 /* ??? There's no reason to disallow this, is there?  */	      if (TREE_READONLY (decl))		error_with_decl (decl, "const objects cannot go in .sdata/.sbss");#endif	      prefix = SDATA_FLAG_CHAR;	    }	}      else	{	  if (TREE_CODE (decl) == VAR_DECL	      && ! TREE_READONLY (decl)	      && ! TARGET_SDATA_NONE)	    {	      int size = int_size_in_bytes (TREE_TYPE (decl));	      if (size > 0 && size <= g_switch_value)		prefix = SDATA_FLAG_CHAR;	    }	}    }  /* If data area not decided yet, check for a code model.  */  if (prefix == 0)    {      if (model)	{	  tree id;	  	  init_idents ();	  id = TREE_VALUE (TREE_VALUE (model));	  if (id == small_ident1 || id == small_ident2)	    ; /* don't mark the symbol specially */	  else if (id == medium_ident1 || id == medium_ident2)	    prefix = MEDIUM_FLAG_CHAR;	  else if (id == large_ident1 || id == large_ident2)	    prefix = LARGE_FLAG_CHAR;	  else	    abort (); /* shouldn't happen */	}      else	{	  if (TARGET_MODEL_SMALL)	    ; /* don't mark the symbol specially */	  else if (TARGET_MODEL_MEDIUM)	    prefix = MEDIUM_FLAG_CHAR;	  else if (TARGET_MODEL_LARGE)	    prefix = LARGE_FLAG_CHAR;	  else	    abort (); /* shouldn't happen */	}    }  if (prefix != 0)    {      rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'                 ? TREE_CST_RTL (decl) : DECL_RTL (decl));      const char *str = XSTR (XEXP (rtl, 0), 0);      int len = strlen (str);      char *newstr = ggc_alloc (len + 2);      strcpy (newstr + 1, str);      *newstr = prefix;      /* Note - we cannot leave the string in the ggc_alloc'ed space.         It must reside in the stringtable's domain.  */      newstr = (char *) ggc_alloc_string (newstr, len + 2);      XSTR (XEXP (rtl, 0), 0) = newstr;    }}/* Do anything needed before RTL is emitted for each function.  */

⌨️ 快捷键说明

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