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

📄 regclass.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Compute register class preferences for pseudo-registers.   Copyright (C) 1987, 1988 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  *//* This file contains two passes of the compiler: reg_scan and reg_class.   It also defines some tables of information about the hardware registers   and a function init_reg_sets to initialize the tables.  */#include "config.h"#include "rtl.h"#include "hard-reg-set.h"#include "flags.h"#include "basic-block.h"#include "regs.h"#include "insn-config.h"#include "recog.h"#define max(A,B) ((A) > (B) ? (A) : (B))#define min(A,B) ((A) < (B) ? (A) : (B))/* Register tables used by many passes.  *//* Indexed by hard register number, contains 1 for registers   that are fixed use (stack pointer, pc, frame pointer, etc.).   These are the registers that cannot be used to allocate   a pseudo reg whose life does not cross calls.  */char fixed_regs[FIRST_PSEUDO_REGISTER];/* Same info as a HARD_REG_SET.  */HARD_REG_SET fixed_reg_set;/* Data for initializing the above.  */static char initial_fixed_regs[] = FIXED_REGISTERS;/* Indexed by hard register number, contains 1 for registers   that are fixed use or are clobbered by function calls.   These are the registers that cannot be used to allocate   a pseudo reg whose life crosses calls.  */char call_used_regs[FIRST_PSEUDO_REGISTER];/* Same info as a HARD_REG_SET.  */HARD_REG_SET call_used_reg_set;/* Data for initializing the above.  */static char initial_call_used_regs[] = CALL_USED_REGISTERS;  /* Indexed by hard register number, contains 1 for registers that are   fixed use -- i.e. in fixed_regs -- or a function value return register   or STRUCT_VALUE_REGNUM or STATIC_CHAIN_REGNUM.  These are the   registers that cannot hold quantities across calls even if we are   willing to save and restore them.  */char call_fixed_regs[FIRST_PSEUDO_REGISTER];/* The same info as a HARD_REG_SET.  */HARD_REG_SET call_fixed_reg_set;/* Indexed by hard register number, contains 1 for registers   that are being used for global register decls.   These must be exempt from ordinary flow analysis   and are also considered fixed.  */char global_regs[FIRST_PSEUDO_REGISTER];  /* Table of register numbers in the order in which to try to use them.  */#ifdef REG_ALLOC_ORDERint reg_alloc_order[FIRST_PSEUDO_REGISTER] = REG_ALLOC_ORDER;#endif/* For each reg class, a HARD_REG_SET saying which registers are in it.  */HARD_REG_SET reg_class_contents[] = REG_CLASS_CONTENTS;/* For each reg class, number of regs it contains.  */int reg_class_size[N_REG_CLASSES];/* For each reg class, table listing all the containing classes.  */enum reg_class reg_class_superclasses[N_REG_CLASSES][N_REG_CLASSES];/* For each reg class, table listing all the classes contained in it.  */enum reg_class reg_class_subclasses[N_REG_CLASSES][N_REG_CLASSES];/* For each pair of reg classes,   a largest reg class contained in their union.  */enum reg_class reg_class_subunion[N_REG_CLASSES][N_REG_CLASSES];/* Array containing all of the register names */char *reg_names[] = REGISTER_NAMES;/* Function called only once to initialize the above data on reg usage.   Once this is done, various switches may override.  */voidinit_reg_sets (){  register int i, j;  bcopy (initial_fixed_regs, fixed_regs, sizeof fixed_regs);  bcopy (initial_call_used_regs, call_used_regs, sizeof call_used_regs);  bzero (global_regs, sizeof global_regs);  /* Compute number of hard regs in each class.  */  bzero (reg_class_size, sizeof reg_class_size);  for (i = 0; i < N_REG_CLASSES; i++)    for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)      if (TEST_HARD_REG_BIT (reg_class_contents[i], j))	reg_class_size[i]++;  /* Initialize the table of subunions.     reg_class_subunion[I][J] gets the largest-numbered reg-class     that is contained in the union of classes I and J.  */  for (i = 0; i < N_REG_CLASSES; i++)    {      for (j = 0; j < N_REG_CLASSES; j++)	{#ifdef HARD_REG_SET	  register		/* Declare it register if it's a scalar.  */#endif	    HARD_REG_SET c;	  register int k;	  COPY_HARD_REG_SET (c, reg_class_contents[i]);	  IOR_HARD_REG_SET (c, reg_class_contents[j]);	  for (k = 0; k < N_REG_CLASSES; k++)	    {	      GO_IF_HARD_REG_SUBSET (reg_class_contents[k], c,				     subclass1);	      continue;	    subclass1:	      reg_class_subunion[i][j] = (enum reg_class) k;	    }	}    }  /* Initialize the tables of subclasses and superclasses of each reg class.     First clear the whole table, then add the elements as they are found.  */  for (i = 0; i < N_REG_CLASSES; i++)    {      for (j = 0; j < N_REG_CLASSES; j++)	{	  reg_class_superclasses[i][j] = LIM_REG_CLASSES;	  reg_class_subclasses[i][j] = LIM_REG_CLASSES;	}    }  for (i = 0; i < N_REG_CLASSES; i++)    {      if (i == (int) NO_REGS)	continue;      for (j = i + 1; j < N_REG_CLASSES; j++)	{	  enum reg_class *p;	  GO_IF_HARD_REG_SUBSET (reg_class_contents[i], reg_class_contents[j],				 subclass);	  continue;	subclass:	  /* Reg class I is a subclass of J.	     Add J to the table of superclasses of I.  */	  p = &reg_class_superclasses[i][0];	  while (*p != LIM_REG_CLASSES) p++;	  *p = (enum reg_class) j;	  /* Add I to the table of superclasses of J.  */	  p = &reg_class_subclasses[j][0];	  while (*p != LIM_REG_CLASSES) p++;	  *p = (enum reg_class) i;	}    }}/* After switches have been processed, which perhaps alter   `fixed_regs' and `call_used_regs', convert them to HARD_REG_SETs.  */voidinit_reg_sets_1 (){  register int i;  /* This macro allows the fixed or call-used registers     to depend on target flags.  */#ifdef CONDITIONAL_REGISTER_USAGE  CONDITIONAL_REGISTER_USAGE;#endif  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)    if (global_regs[i])      {	if (call_used_regs[i] && ! fixed_regs[i])	  warning ("call-clobbered register used for global register variable");	fixed_regs[i] = 1;	/* Prevent saving/restoring of this reg.  */	call_used_regs[i] = 1;      }  /* Initialize "constant" tables.  */  CLEAR_HARD_REG_SET (fixed_reg_set);  CLEAR_HARD_REG_SET (call_used_reg_set);  CLEAR_HARD_REG_SET (call_fixed_reg_set);  bcopy (fixed_regs, call_fixed_regs, sizeof call_fixed_regs);#ifdef STRUCT_VALUE_REGNUM  call_fixed_regs[STRUCT_VALUE_REGNUM] = 1;#endif#ifdef STATIC_CHAIN_REGNUM  call_fixed_regs[STATIC_CHAIN_REGNUM] = 1;#endif  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)    {      if (FUNCTION_VALUE_REGNO_P (i))	call_fixed_regs[i] = 1;      if (fixed_regs[i])	SET_HARD_REG_BIT (fixed_reg_set, i);      if (call_used_regs[i])	SET_HARD_REG_BIT (call_used_reg_set, i);      if (call_fixed_regs[i])	SET_HARD_REG_BIT (call_fixed_reg_set, i);    }}/* Specify the usage characteristics of the register named NAME.   It should be a fixed register if FIXED and a   call-used register if CALL_USED.  */voidfix_register (name, fixed, call_used)     char *name;     int fixed, call_used;{  int i;  /* Decode the name and update the primary form of     the register info.  */  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)    if (!strcmp (reg_names[i], name))      {	fixed_regs[i] = fixed;	call_used_regs[i] = call_used;	break;      }  if (i == FIRST_PSEUDO_REGISTER)    {      warning ("unknown register name: %s", name);      return;    }}/* Now the data and code for the `regclass' pass, which happens   just before local-alloc.  *//* savings[R].savings[CL] is twice the amount saved by putting register R   in class CL.  This data is used within `regclass' and freed   when it is finished.  */struct savings{  short savings[N_REG_CLASSES];  short memcost;  short nrefs;};static struct savings *savings;/* (enum reg_class) prefclass[R] is the preferred class for pseudo number R.   This is available after `regclass' is run.  */static char *prefclass;/* preferred_or_nothing[R] is nonzero if we should put pseudo number R   in memory if we can't get its perferred class.   This is available after `regclass' is run.  */static char *preferred_or_nothing;void reg_class_record ();void record_address_regs ();/* Return the reg_class in which pseudo reg number REGNO is best allocated.   This function is sometimes called before the info has been computed.   When that happens, just return GENERAL_REGS, which is innocuous.  */enum reg_classreg_preferred_class (regno)     int regno;{  if (prefclass == 0)    return GENERAL_REGS;  return (enum reg_class) prefclass[regno];}intreg_preferred_or_nothing (regno){  if (prefclass == 0)    return 0;  return preferred_or_nothing[regno];}/* This prevents dump_flow_info from losing if called   before regclass is run.  */intregclass_init (){  prefclass = 0;}/* This is a pass of the compiler that scans all instructions   and calculates the preferred class for each pseudo-register.   This information can be accessed later by calling `reg_preferred_class'.   This pass comes just before local register allocation.  */voidregclass (f, nregs)     rtx f;     int nregs;{#ifdef REGISTER_CONSTRAINTS  register rtx insn;  register int i;  init_recog ();  /* Zero out our accumulation of the cost of each class for each reg.  */  savings = (struct savings *) alloca (nregs * sizeof (struct savings));  bzero (savings, nregs * sizeof (struct savings));  /* Scan the instructions and record each time it would     save code to put a certain register in a certain class.  */  for (insn = f; insn; insn = NEXT_INSN (insn))    if ((GET_CODE (insn) == INSN	 && GET_CODE (PATTERN (insn)) != USE	 && GET_CODE (PATTERN (insn)) != CLOBBER	 && GET_CODE (PATTERN (insn)) != ASM_INPUT)	|| (GET_CODE (insn) == JUMP_INSN	    && GET_CODE (PATTERN (insn)) != ADDR_VEC	    && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)	|| GET_CODE (insn) == CALL_INSN)      {	if (GET_CODE (insn) == INSN && asm_noperands (PATTERN (insn)) >= 0)	  {	    int noperands = asm_noperands (PATTERN (insn));	    /* We don't use alloca because alloca would not free	       any of the space until this function returns.  */	    rtx *operands = (rtx *) oballoc (noperands * sizeof (rtx));	    char **constraints	      = (char **) oballoc (noperands * sizeof (char *));	    decode_asm_operands (PATTERN (insn), operands, 0, constraints, 0);	    for (i = noperands - 1; i >= 0; i--)	      reg_class_record (operands[i], i, constraints);	    obfree (operands);	  }	else	  {	    int insn_code_number = recog_memoized (insn);	    insn_extract (insn);	    for (i = insn_n_operands[insn_code_number] - 1; i >= 0; i--)	      reg_class_record (recog_operand[i], i,				insn_operand_constraint[insn_code_number]);	    /* Improve handling of two-address insns such as	       (set X (ashift CONST Y)) where CONST must be made to match X.	       Change it into two insns: (set X CONST)  (set X (ashift X Y)).	       If we left this for reloading, it would probably get three insns	       because X and Y might go in the same place.	       This prevents X and Y from receiving the same hard reg.  */	    if (optimize		&& insn_n_operands[insn_code_number] >= 3		&& insn_operand_constraint[insn_code_number][1][0] == '0'		&& insn_operand_constraint[insn_code_number][1][1] == 0		&& CONSTANT_P (recog_operand[1])		&& ! rtx_equal_p (recog_operand[0], recog_operand[1])		&& ! rtx_equal_p (recog_operand[0], recog_operand[2])		&& GET_CODE (recog_operand[0]) == REG)	      {		rtx previnsn = prev_real_insn (insn);		rtx newinsn		  = emit_insn_before (gen_move_insn (recog_operand[0],						     recog_operand[1]),				      insn);		/* If this insn was the start of a basic block,		   include the new insn in that block.  */		if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN)		  {		    int b;		    for (b = 0; b < n_basic_blocks; b++)		      if (insn == basic_block_head[b])			basic_block_head[b] = newinsn;		  }		/* This makes one more setting of new insns's destination.  */		reg_n_sets[REGNO (recog_operand[0])]++;		*recog_operand_loc[1] = recog_operand[0];		for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--)		  if (recog_dup_num[i] == 1)		    *recog_dup_loc[i] = recog_operand[0];	      }	  }      }  /* Now for each register look at how desirable each class is

⌨️ 快捷键说明

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