📄 regclass.c
字号:
/* 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 = ®_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 = ®_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 + -