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

📄 local-alloc.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Allocate registers within a basic block, for GNU compiler.   Copyright (C) 1987, 88, 91, 93, 94, 1995 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.  *//* Allocation of hard register numbers to pseudo registers is done in   two passes.  In this pass we consider only regs that are born and   die once within one basic block.  We do this one basic block at a   time.  Then the next pass allocates the registers that remain.   Two passes are used because this pass uses methods that work only   on linear code, but that do a better job than the general methods   used in global_alloc, and more quickly too.   The assignments made are recorded in the vector reg_renumber   whose space is allocated here.  The rtl code itself is not altered.   We assign each instruction in the basic block a number   which is its order from the beginning of the block.   Then we can represent the lifetime of a pseudo register with   a pair of numbers, and check for conflicts easily.   We can record the availability of hard registers with a   HARD_REG_SET for each instruction.  The HARD_REG_SET   contains 0 or 1 for each hard reg.   To avoid register shuffling, we tie registers together when one   dies by being copied into another, or dies in an instruction that   does arithmetic to produce another.  The tied registers are   allocated as one.  Registers with different reg class preferences   can never be tied unless the class preferred by one is a subclass   of the one preferred by the other.   Tying is represented with "quantity numbers".   A non-tied register is given a new quantity number.   Tied registers have the same quantity number.      We have provision to exempt registers, even when they are contained   within the block, that can be tied to others that are not contained in it.   This is so that global_alloc could process them both and tie them then.   But this is currently disabled since tying in global_alloc is not   yet implemented.  */#include <stdio.h>#include "config.h"#include "rtl.h"#include "flags.h"#include "basic-block.h"#include "regs.h"#include "hard-reg-set.h"#include "insn-config.h"#include "recog.h"#include "output.h"/* Pseudos allocated here cannot be reallocated by global.c if the hard   register is used as a spill register.  So we don't allocate such pseudos   here if their preferred class is likely to be used by spills.   On most machines, the appropriate test is if the class has one   register, so we default to that.  */#ifndef CLASS_LIKELY_SPILLED_P#define CLASS_LIKELY_SPILLED_P(CLASS) (reg_class_size[(int) (CLASS)] == 1)#endif/* Next quantity number available for allocation.  */static int next_qty;/* In all the following vectors indexed by quantity number.  *//* Element Q is the hard reg number chosen for quantity Q,   or -1 if none was found.  */static short *qty_phys_reg;/* We maintain two hard register sets that indicate suggested hard registers   for each quantity.  The first, qty_phys_copy_sugg, contains hard registers   that are tied to the quantity by a simple copy.  The second contains all   hard registers that are tied to the quantity via an arithmetic operation.   The former register set is given priority for allocation.  This tends to   eliminate copy insns.  *//* Element Q is a set of hard registers that are suggested for quantity Q by   copy insns.  */static HARD_REG_SET *qty_phys_copy_sugg;/* Element Q is a set of hard registers that are suggested for quantity Q by   arithmetic insns.  */static HARD_REG_SET *qty_phys_sugg;/* Element Q is the number of suggested registers in qty_phys_copy_sugg.  */static short *qty_phys_num_copy_sugg;/* Element Q is the number of suggested registers in qty_phys_sugg. */static short *qty_phys_num_sugg;/* Element Q is the number of refs to quantity Q.  */static int *qty_n_refs;/* Element Q is a reg class contained in (smaller than) the   preferred classes of all the pseudo regs that are tied in quantity Q.   This is the preferred class for allocating that quantity.  */static enum reg_class *qty_min_class;/* Insn number (counting from head of basic block)   where quantity Q was born.  -1 if birth has not been recorded.  */static int *qty_birth;/* Insn number (counting from head of basic block)   where quantity Q died.  Due to the way tying is done,   and the fact that we consider in this pass only regs that die but once,   a quantity can die only once.  Each quantity's life span   is a set of consecutive insns.  -1 if death has not been recorded.  */static int *qty_death;/* Number of words needed to hold the data in quantity Q.   This depends on its machine mode.  It is used for these purposes:   1. It is used in computing the relative importances of qtys,      which determines the order in which we look for regs for them.   2. It is used in rules that prevent tying several registers of      different sizes in a way that is geometrically impossible      (see combine_regs).  */static int *qty_size;/* This holds the mode of the registers that are tied to qty Q,   or VOIDmode if registers with differing modes are tied together.  */static enum machine_mode *qty_mode;/* Number of times a reg tied to qty Q lives across a CALL_INSN.  */static int *qty_n_calls_crossed;/* Register class within which we allocate qty Q if we can't get   its preferred class.  */static enum reg_class *qty_alternate_class;/* Element Q is the SCRATCH expression for which this quantity is being   allocated or 0 if this quantity is allocating registers.  */static rtx *qty_scratch_rtx;/* Element Q is nonzero if this quantity has been used in a SUBREG   that changes its size.  */static char *qty_changes_size;/* Element Q is the register number of one pseudo register whose   reg_qty value is Q, or -1 is this quantity is for a SCRATCH.  This   register should be the head of the chain maintained in reg_next_in_qty.  */static int *qty_first_reg;/* If (REG N) has been assigned a quantity number, is a register number   of another register assigned the same quantity number, or -1 for the   end of the chain.  qty_first_reg point to the head of this chain.  */static int *reg_next_in_qty;/* reg_qty[N] (where N is a pseudo reg number) is the qty number of that reg   if it is >= 0,   of -1 if this register cannot be allocated by local-alloc,   or -2 if not known yet.   Note that if we see a use or death of pseudo register N with   reg_qty[N] == -2, register N must be local to the current block.  If   it were used in more than one block, we would have reg_qty[N] == -1.   This relies on the fact that if reg_basic_block[N] is >= 0, register N   will not appear in any other block.  We save a considerable number of   tests by exploiting this.   If N is < FIRST_PSEUDO_REGISTER, reg_qty[N] is undefined and should not   be referenced.  */static int *reg_qty;/* The offset (in words) of register N within its quantity.   This can be nonzero if register N is SImode, and has been tied   to a subreg of a DImode register.  */static char *reg_offset;/* Vector of substitutions of register numbers,   used to map pseudo regs into hardware regs.   This is set up as a result of register allocation.   Element N is the hard reg assigned to pseudo reg N,   or is -1 if no hard reg was assigned.   If N is a hard reg number, element N is N.  */short *reg_renumber;/* Set of hard registers live at the current point in the scan   of the instructions in a basic block.  */static HARD_REG_SET regs_live;/* Each set of hard registers indicates registers live at a particular   point in the basic block.  For N even, regs_live_at[N] says which   hard registers are needed *after* insn N/2 (i.e., they may not   conflict with the outputs of insn N/2 or the inputs of insn N/2 + 1.   If an object is to conflict with the inputs of insn J but not the   outputs of insn J + 1, we say it is born at index J*2 - 1.  Similarly,   if it is to conflict with the outputs of insn J but not the inputs of   insn J + 1, it is said to die at index J*2 + 1.  */static HARD_REG_SET *regs_live_at;int *scratch_block;rtx *scratch_list;int scratch_list_length;static int scratch_index;/* Communicate local vars `insn_number' and `insn'   from `block_alloc' to `reg_is_set', `wipe_dead_reg', and `alloc_qty'.  */static int this_insn_number;static rtx this_insn;static void alloc_qty		PROTO((int, enum machine_mode, int, int));static void alloc_qty_for_scratch PROTO((rtx, int, rtx, int, int));static void validate_equiv_mem_from_store PROTO((rtx, rtx));static int validate_equiv_mem	PROTO((rtx, rtx, rtx));static int memref_referenced_p	PROTO((rtx, rtx));static int memref_used_between_p PROTO((rtx, rtx, rtx));static void optimize_reg_copy_1	PROTO((rtx, rtx, rtx));static void optimize_reg_copy_2	PROTO((rtx, rtx, rtx));static void update_equiv_regs	PROTO((void));static void block_alloc		PROTO((int));static int qty_sugg_compare    	PROTO((int, int));static int qty_sugg_compare_1	PROTO((int *, int *));static int qty_compare    	PROTO((int, int));static int qty_compare_1	PROTO((int *, int *));static int combine_regs		PROTO((rtx, rtx, int, int, rtx, int));static int reg_meets_class_p	PROTO((int, enum reg_class));static int reg_classes_overlap_p PROTO((enum reg_class, enum reg_class,					int));static void update_qty_class	PROTO((int, int));static void reg_is_set		PROTO((rtx, rtx));static void reg_is_born		PROTO((rtx, int));static void wipe_dead_reg	PROTO((rtx, int));static int find_free_reg	PROTO((enum reg_class, enum machine_mode,				       int, int, int, int, int));static void mark_life		PROTO((int, enum machine_mode, int));static void post_mark_life	PROTO((int, enum machine_mode, int, int, int));static int no_conflict_p	PROTO((rtx, rtx, rtx));static int requires_inout	PROTO((char *));/* Allocate a new quantity (new within current basic block)   for register number REGNO which is born at index BIRTH   within the block.  MODE and SIZE are info on reg REGNO.  */static voidalloc_qty (regno, mode, size, birth)     int regno;     enum machine_mode mode;     int size, birth;{  register int qty = next_qty++;  reg_qty[regno] = qty;  reg_offset[regno] = 0;  reg_next_in_qty[regno] = -1;  qty_first_reg[qty] = regno;  qty_size[qty] = size;  qty_mode[qty] = mode;  qty_birth[qty] = birth;  qty_n_calls_crossed[qty] = reg_n_calls_crossed[regno];  qty_min_class[qty] = reg_preferred_class (regno);  qty_alternate_class[qty] = reg_alternate_class (regno);  qty_n_refs[qty] = reg_n_refs[regno];  qty_changes_size[qty] = reg_changes_size[regno];}/* Similar to `alloc_qty', but allocates a quantity for a SCRATCH rtx   used as operand N in INSN.  We assume here that the SCRATCH is used in   a CLOBBER.  */static voidalloc_qty_for_scratch (scratch, n, insn, insn_code_num, insn_number)     rtx scratch;     int n;     rtx insn;     int insn_code_num, insn_number;{  register int qty;  enum reg_class class;  char *p, c;  int i;#ifdef REGISTER_CONSTRAINTS  /* If we haven't yet computed which alternative will be used, do so now.     Then set P to the constraints for that alternative.  */  if (which_alternative == -1)    if (! constrain_operands (insn_code_num, 0))      return;  for (p = insn_operand_constraint[insn_code_num][n], i = 0;       *p && i < which_alternative; p++)    if (*p == ',')      i++;  /* Compute the class required for this SCRATCH.  If we don't need a     register, the class will remain NO_REGS.  If we guessed the alternative     number incorrectly, reload will fix things up for us.  */  class = NO_REGS;  while ((c = *p++) != '\0' && c != ',')    switch (c)      {      case '=':  case '+':  case '?':      case '#':  case '&':  case '!':      case '*':  case '%':        case '0':  case '1':  case '2':  case '3':  case '4':      case 'm':  case '<':  case '>':  case 'V':  case 'o':      case 'E':  case 'F':  case 'G':  case 'H':      case 's':  case 'i':  case 'n':      case 'I':  case 'J':  case 'K':  case 'L':      case 'M':  case 'N':  case 'O':  case 'P':#ifdef EXTRA_CONSTRAINT      case 'Q':  case 'R':  case 'S':  case 'T':  case 'U':#endif      case 'p':	/* These don't say anything we care about.  */	break;      case 'X':	/* We don't need to allocate this SCRATCH.  */	return;      case 'g': case 'r':	class = reg_class_subunion[(int) class][(int) GENERAL_REGS];	break;      default:	class	  = reg_class_subunion[(int) class][(int) REG_CLASS_FROM_LETTER (c)];	break;      }  if (class == NO_REGS)    return;#else /* REGISTER_CONSTRAINTS */  class = GENERAL_REGS;#endif    qty = next_qty++;  qty_first_reg[qty] = -1;  qty_scratch_rtx[qty] = scratch;  qty_size[qty] = GET_MODE_SIZE (GET_MODE (scratch));  qty_mode[qty] = GET_MODE (scratch);  qty_birth[qty] = 2 * insn_number - 1;  qty_death[qty] = 2 * insn_number + 1;  qty_n_calls_crossed[qty] = 0;  qty_min_class[qty] = class;  qty_alternate_class[qty] = NO_REGS;  qty_n_refs[qty] = 1;  qty_changes_size[qty] = 0;}/* Main entry point of this file.  */voidlocal_alloc (){

⌨️ 快捷键说明

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