📄 local-alloc.c
字号:
/* Allocate registers within a basic block, for GNU compiler. Copyright (C) 1987, 1988, 1991 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, 675 Mass Ave, Cambridge, MA 02139, 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"/* 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 non-zero if there is a suggested register in qty_phys_copy_sugg. */static char *qty_phys_has_copy_sugg;/* Element Q is non-zero if there is a suggested register in qty_phys_sugg. */static char *qty_phys_has_sugg;/* Element Q is the number of refs to quantity Q. */static short *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 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 short *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 short *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;/* 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 block_alloc ();static void update_equiv_regs ();static int no_conflict_p ();static int combine_regs ();static void wipe_dead_reg ();static int find_free_reg ();static void reg_is_born ();static void reg_is_set ();static void mark_life ();static void post_mark_life ();static int qty_compare ();static int qty_compare_1 ();static int reg_meets_class_p ();static void update_qty_class ();static int requires_inout_p ();/* 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];}/* 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 has only one register, don't allocate the SCRATCH here since it will prevent that register from being used as a spill register. reload will do the allocation. */ if (class == NO_REGS || reg_class_size[(int) class] == 1) 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;}/* Main entry point of this file. */voidlocal_alloc (){ register int b, i; int max_qty; /* Leaf functions and non-leaf functions have different needs. If defined, let the machine say what kind of ordering we should use. */#ifdef ORDER_REGS_FOR_LOCAL_ALLOC ORDER_REGS_FOR_LOCAL_ALLOC;#endif /* Promote REG_EQUAL notes to REG_EQUIV notes and adjust status of affected registers. */ update_equiv_regs (); /* This sets the maximum number of quantities we can have. Quantity numbers start at zero and we can have one for each pseudo plus the number of SCRATCHes in the largest block, in the worst case. */ max_qty = (max_regno - FIRST_PSEUDO_REGISTER) + max_scratch; /* Allocate vectors of temporary data. See the declarations of these variables, above, for what they mean. */ qty_phys_reg = (short *) alloca (max_qty * sizeof (short)); qty_phys_copy_sugg = (HARD_REG_SET *) alloca (max_qty * sizeof (HARD_REG_SET)); qty_phys_has_copy_sugg = (char *) alloca (max_qty * sizeof (char)); qty_phys_sugg = (HARD_REG_SET *) alloca (max_qty * sizeof (HARD_REG_SET)); qty_phys_has_sugg = (char *) alloca (max_qty * sizeof (char)); qty_birth = (int *) alloca (max_qty * sizeof (int)); qty_death = (int *) alloca (max_qty * sizeof (int)); qty_scratch_rtx = (rtx *) alloca (max_qty * sizeof (rtx)); qty_first_reg = (short *) alloca (max_qty * sizeof (short)); qty_size = (int *) alloca (max_qty * sizeof (int)); qty_mode = (enum machine_mode *) alloca (max_qty * sizeof (enum machine_mode)); qty_n_calls_crossed = (int *) alloca (max_qty * sizeof (int)); qty_min_class = (enum reg_class *) alloca (max_qty * sizeof (enum reg_class)); qty_alternate_class = (enum reg_class *) alloca (max_qty * sizeof (enum reg_class)); qty_n_refs = (short *) alloca (max_qty * sizeof (short));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -