📄 local-alloc.c
字号:
/* 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 + -