mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-23 01:40:32 +08:00
common.opt (-fnew-ra): Remove.
2005-01-17 Paolo Bonzini <bonzini@gnu.org> * common.opt (-fnew-ra): Remove. * ra*.*: Remove. * toplev.h (flag_new_regalloc): Remove. * Makefile.in (ra*.*): Don't mention. * passes.c (rest_of_handle_new_regalloc): Remove. (rest_of_handle_combine, rest_of_compilation): Always consider flag_new_regalloc as false. * doc/invoke.texi: Don't document -fnew-ra. From-SVN: r93759
This commit is contained in:
parent
c80a0f261b
commit
cd280abb0e
@ -1,4 +1,15 @@
|
||||
2005-01-15 Paolo Bonzini <bonzini@gnu.org>
|
||||
2005-01-17 Paolo Bonzini <bonzini@gnu.org>
|
||||
|
||||
* common.opt (-fnew-ra): Remove.
|
||||
* ra*.*: Remove.
|
||||
* toplev.h (flag_new_regalloc): Remove.
|
||||
* Makefile.in (ra*.*): Don't mention.
|
||||
* passes.c (rest_of_handle_new_regalloc): Remove.
|
||||
(rest_of_handle_combine, rest_of_compilation): Always consider
|
||||
flag_new_regalloc as false.
|
||||
* doc/invoke.texi: Don't document -fnew-ra.
|
||||
|
||||
2005-01-17 Paolo Bonzini <bonzini@gnu.org>
|
||||
|
||||
* bb-reorder.c (fix_edges_for_rarely_executed_code): Remove
|
||||
last parameter to reg_scan.
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Run 'configure' to generate Makefile from Makefile.in
|
||||
|
||||
# Copyright (C) 1987, 1988, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
|
||||
# 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||
# 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
|
||||
#This file is part of GCC.
|
||||
|
||||
@ -704,7 +704,6 @@ FLAGS_H = flags.h options.h
|
||||
EXPR_H = expr.h insn-config.h function.h $(RTL_H) $(FLAGS_H) $(TREE_H) $(MACHMODE_H) $(EMIT_RTL_H)
|
||||
OPTABS_H = optabs.h insn-codes.h
|
||||
REGS_H = regs.h varray.h $(MACHMODE_H) $(OBSTACK_H) $(BASIC_BLOCK_H)
|
||||
RA_H = ra.h bitmap.h sbitmap.h hard-reg-set.h insn-modes.h
|
||||
RESOURCE_H = resource.h hard-reg-set.h
|
||||
SCHED_INT_H = sched-int.h $(INSN_ATTR_H) $(BASIC_BLOCK_H) $(RTL_H)
|
||||
INTEGRATE_H = integrate.h varray.h
|
||||
@ -920,8 +919,7 @@ OBJS-common = \
|
||||
loop.o modulo-sched.o optabs.o options.o opts.o \
|
||||
params.o postreload.o postreload-gcse.o predict.o \
|
||||
insn-preds.o pointer-set.o postreload.o \
|
||||
print-rtl.o print-tree.o value-prof.o var-tracking.o \
|
||||
profile.o ra.o ra-build.o ra-colorize.o ra-debug.o ra-rewrite.o \
|
||||
print-rtl.o print-tree.o profile.o value-prof.o var-tracking.o \
|
||||
real.o recog.o reg-stack.o regclass.o regmove.o regrename.o \
|
||||
reload.o reload1.o reorg.o resource.o rtl.o rtlanal.o rtl-error.o \
|
||||
sbitmap.o sched-deps.o sched-ebb.o sched-rgn.o sched-vis.o sdbout.o \
|
||||
@ -2067,20 +2065,6 @@ global.o : global.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(FLAGS
|
||||
varray.o : varray.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) varray.h $(GGC_H) errors.h \
|
||||
$(HASHTAB_H)
|
||||
vec.o : vec.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) coretypes.h vec.h $(GGC_H) errors.h
|
||||
ra.o : ra.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TM_P_H) insn-config.h \
|
||||
$(RECOG_H) $(INTEGRATE_H) function.h $(REGS_H) $(OBSTACK_H) hard-reg-set.h \
|
||||
$(BASIC_BLOCK_H) $(DF_H) $(EXPR_H) output.h toplev.h $(FLAGS_H) reload.h $(RA_H)
|
||||
ra-build.o : ra-build.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TM_P_H) \
|
||||
insn-config.h $(RECOG_H) function.h $(REGS_H) hard-reg-set.h \
|
||||
$(BASIC_BLOCK_H) $(DF_H) output.h $(GGC_H) $(RA_H) gt-ra-build.h reload.h
|
||||
ra-colorize.o : ra-colorize.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||
$(TM_P_H) function.h $(REGS_H) hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) output.h $(RA_H)
|
||||
ra-debug.o : ra-debug.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||
insn-config.h $(RECOG_H) function.h hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) output.h \
|
||||
$(RA_H) $(TM_P_H) $(REGS_H)
|
||||
ra-rewrite.o : ra-rewrite.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||
$(TM_P_H) function.h $(REGS_H) hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) $(EXPR_H) \
|
||||
output.h except.h $(RA_H) reload.h insn-config.h
|
||||
reload.o : reload.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(FLAGS_H) output.h \
|
||||
$(EXPR_H) $(OPTABS_H) reload.h $(RECOG_H) hard-reg-set.h insn-config.h \
|
||||
$(REGS_H) function.h real.h toplev.h $(TM_P_H) $(PARAMS_H)
|
||||
@ -2432,7 +2416,7 @@ GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \
|
||||
$(srcdir)/emit-rtl.c $(srcdir)/except.c $(srcdir)/explow.c $(srcdir)/expr.c \
|
||||
$(srcdir)/function.c \
|
||||
$(srcdir)/gcse.c $(srcdir)/integrate.c $(srcdir)/lists.c $(srcdir)/optabs.c \
|
||||
$(srcdir)/profile.c $(srcdir)/ra-build.c $(srcdir)/regclass.c \
|
||||
$(srcdir)/profile.c $(srcdir)/regclass.c \
|
||||
$(srcdir)/reg-stack.c $(srcdir)/cfglayout.c \
|
||||
$(srcdir)/sdbout.c $(srcdir)/stor-layout.c \
|
||||
$(srcdir)/stringpool.c $(srcdir)/tree.c $(srcdir)/varasm.c \
|
||||
@ -2458,7 +2442,7 @@ gt-function.h gt-integrate.h gt-tree.h gt-varasm.h \
|
||||
gt-emit-rtl.h gt-explow.h gt-stor-layout.h gt-regclass.h \
|
||||
gt-lists.h gt-alias.h gt-cselib.h gt-gcse.h \
|
||||
gt-expr.h gt-sdbout.h gt-optabs.h gt-bitmap.h gt-dojump.h \
|
||||
gt-dwarf2out.h gt-ra-build.h gt-reg-stack.h gt-dwarf2asm.h \
|
||||
gt-dwarf2out.h gt-reg-stack.h gt-dwarf2asm.h \
|
||||
gt-dbxout.h gt-c-common.h gt-c-decl.h gt-c-parse.h \
|
||||
gt-c-pragma.h gtype-c.h gt-cfglayout.h \
|
||||
gt-tree-mudflap.h gt-tree-complex.h \
|
||||
|
@ -1,6 +1,6 @@
|
||||
; Options for the language- and target-independent parts of the compiler.
|
||||
|
||||
; Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
; Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
;
|
||||
; This file is part of GCC.
|
||||
;
|
||||
@ -539,10 +539,6 @@ fmudflapir
|
||||
Common RejectNegative Report Var(flag_mudflap_ignore_reads)
|
||||
Ignore read operations when inserting mudflap instrumentation.
|
||||
|
||||
fnew-ra
|
||||
Common Report Var(flag_new_regalloc)
|
||||
Use graph-coloring register allocation
|
||||
|
||||
freschedule-modulo-scheduled-loops
|
||||
Common Report Var(flag_resched_modulo_sched)
|
||||
Enable/Disable the traditional scheduling in loops that already passed modulo scheduling
|
||||
|
@ -294,7 +294,7 @@ Objective-C and Objective-C++ Dialects}.
|
||||
-floop-optimize -fcrossjumping -fif-conversion -fif-conversion2 @gol
|
||||
-finline-functions -finline-limit=@var{n} -fkeep-inline-functions @gol
|
||||
-fkeep-static-consts -fmerge-constants -fmerge-all-constants @gol
|
||||
-fmodulo-sched -fnew-ra -fno-branch-count-reg @gol
|
||||
-fmodulo-sched -fno-branch-count-reg @gol
|
||||
-fno-default-inline -fno-defer-pop -floop-optimize2 -fmove-loop-invariants @gol
|
||||
-fno-function-cse -fno-guess-branch-probability @gol
|
||||
-fno-inline -fno-math-errno -fno-peephole -fno-peephole2 @gol
|
||||
@ -4282,12 +4282,6 @@ Perform swing modulo scheduling immediately before the first scheduling
|
||||
pass. This pass looks at innermost loops and reorders their
|
||||
instructions by overlapping different iterations.
|
||||
|
||||
@item -fnew-ra
|
||||
@opindex fnew-ra
|
||||
Use a graph coloring register allocator. Currently this option is meant
|
||||
only for testing. Users should not specify this option, since it is not
|
||||
yet ready for production use.
|
||||
|
||||
@item -fno-branch-count-reg
|
||||
@opindex fno-branch-count-reg
|
||||
Do not use ``decrement and branch'' instructions on a count register,
|
||||
@ -5211,12 +5205,6 @@ a ``home register''.
|
||||
|
||||
Not enabled by default at any level because it has known bugs.
|
||||
|
||||
@item -fnew-ra
|
||||
@opindex fnew-ra
|
||||
Use a graph coloring register allocator. Currently this option is meant
|
||||
for testing, so we are interested to hear about miscompilations with
|
||||
@option{-fnew-ra}.
|
||||
|
||||
@item -ftracer
|
||||
@opindex ftracer
|
||||
Perform tail duplication to enlarge superblock size. This transformation
|
||||
|
59
gcc/passes.c
59
gcc/passes.c
@ -1,6 +1,6 @@
|
||||
/* Top level of GCC compilers (cc1, cc1plus, etc.)
|
||||
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
|
||||
1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||
1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
@ -425,49 +425,6 @@ rest_of_handle_machine_reorg (void)
|
||||
}
|
||||
|
||||
|
||||
/* Run new register allocator. Return TRUE if we must exit
|
||||
rest_of_compilation upon return. */
|
||||
static bool
|
||||
rest_of_handle_new_regalloc (void)
|
||||
{
|
||||
int failure;
|
||||
|
||||
timevar_push (TV_LOCAL_ALLOC);
|
||||
open_dump_file (DFI_lreg, current_function_decl);
|
||||
|
||||
delete_trivially_dead_insns (get_insns (), max_reg_num ());
|
||||
reg_alloc ();
|
||||
|
||||
timevar_pop (TV_LOCAL_ALLOC);
|
||||
close_dump_file (DFI_lreg, NULL, NULL);
|
||||
|
||||
/* XXX clean up the whole mess to bring live info in shape again. */
|
||||
timevar_push (TV_GLOBAL_ALLOC);
|
||||
open_dump_file (DFI_greg, current_function_decl);
|
||||
|
||||
build_insn_chain (get_insns ());
|
||||
failure = reload (get_insns (), 0);
|
||||
|
||||
timevar_pop (TV_GLOBAL_ALLOC);
|
||||
|
||||
ggc_collect ();
|
||||
|
||||
if (dump_enabled_p (DFI_greg))
|
||||
{
|
||||
timevar_push (TV_DUMP);
|
||||
dump_global_regs (dump_file);
|
||||
timevar_pop (TV_DUMP);
|
||||
close_dump_file (DFI_greg, print_rtl_with_bb, get_insns ());
|
||||
}
|
||||
|
||||
if (failure)
|
||||
return true;
|
||||
|
||||
reload_completed = 1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Run old register allocator. Return TRUE if we must exit
|
||||
rest_of_compilation upon return. */
|
||||
static bool
|
||||
@ -970,7 +927,7 @@ rest_of_handle_life (void)
|
||||
|
||||
if (optimize)
|
||||
{
|
||||
if (!flag_new_regalloc && initialize_uninitialized_subregs ())
|
||||
if (initialize_uninitialized_subregs ())
|
||||
{
|
||||
/* Insns were inserted, and possibly pseudos created, so
|
||||
things might look a bit different. */
|
||||
@ -1706,16 +1663,8 @@ rest_of_compilation (void)
|
||||
epilogue thus changing register elimination offsets. */
|
||||
current_function_is_leaf = leaf_function_p ();
|
||||
|
||||
if (flag_new_regalloc)
|
||||
{
|
||||
if (rest_of_handle_new_regalloc ())
|
||||
goto exit_rest_of_compilation;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rest_of_handle_old_regalloc ())
|
||||
goto exit_rest_of_compilation;
|
||||
}
|
||||
if (rest_of_handle_old_regalloc ())
|
||||
goto exit_rest_of_compilation;
|
||||
|
||||
if (optimize > 0)
|
||||
rest_of_handle_postreload ();
|
||||
|
3172
gcc/ra-build.c
3172
gcc/ra-build.c
File diff suppressed because it is too large
Load Diff
2739
gcc/ra-colorize.c
2739
gcc/ra-colorize.c
File diff suppressed because it is too large
Load Diff
1100
gcc/ra-debug.c
1100
gcc/ra-debug.c
File diff suppressed because it is too large
Load Diff
1963
gcc/ra-rewrite.c
1963
gcc/ra-rewrite.c
File diff suppressed because it is too large
Load Diff
924
gcc/ra.c
924
gcc/ra.c
@ -1,924 +0,0 @@
|
||||
/* Graph coloring register allocator
|
||||
Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||
Contributed by Michael Matz <matz@suse.de>
|
||||
and Daniel Berlin <dan@cgsoftware.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 2, or (at your option) any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with GCC; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tm.h"
|
||||
#include "rtl.h"
|
||||
#include "tm_p.h"
|
||||
#include "insn-config.h"
|
||||
#include "recog.h"
|
||||
#include "reload.h"
|
||||
#include "integrate.h"
|
||||
#include "function.h"
|
||||
#include "regs.h"
|
||||
#include "obstack.h"
|
||||
#include "hard-reg-set.h"
|
||||
#include "basic-block.h"
|
||||
#include "df.h"
|
||||
#include "expr.h"
|
||||
#include "output.h"
|
||||
#include "toplev.h"
|
||||
#include "flags.h"
|
||||
#include "ra.h"
|
||||
|
||||
/* This is the toplevel file of a graph coloring register allocator.
|
||||
It is able to act like a George & Appel allocator, i.e. with iterative
|
||||
coalescing plus spill coalescing/propagation.
|
||||
And it can act as a traditional Briggs allocator, although with
|
||||
optimistic coalescing. Additionally it has a custom pass, which
|
||||
tries to reduce the overall cost of the colored graph.
|
||||
|
||||
We support two modes of spilling: spill-everywhere, which is extremely
|
||||
fast, and interference region spilling, which reduces spill code to a
|
||||
large extent, but is slower.
|
||||
|
||||
Helpful documents:
|
||||
|
||||
Briggs, P., Cooper, K. D., and Torczon, L. 1994. Improvements to graph
|
||||
coloring register allocation. ACM Trans. Program. Lang. Syst. 16, 3 (May),
|
||||
428-455.
|
||||
|
||||
Bergner, P., Dahl, P., Engebretsen, D., and O'Keefe, M. 1997. Spill code
|
||||
minimization via interference region spilling. In Proc. ACM SIGPLAN '97
|
||||
Conf. on Prog. Language Design and Implementation. ACM, 287-295.
|
||||
|
||||
George, L., Appel, A.W. 1996. Iterated register coalescing.
|
||||
ACM Trans. Program. Lang. Syst. 18, 3 (May), 300-324.
|
||||
|
||||
*/
|
||||
|
||||
/* This file contains the main entry point (reg_alloc), some helper routines
|
||||
used by more than one file of the register allocator, and the toplevel
|
||||
driver procedure (one_pass). */
|
||||
|
||||
/* Things, one might do somewhen:
|
||||
|
||||
* Lattice based rematerialization
|
||||
* create definitions of ever-life regs at the beginning of
|
||||
the insn chain
|
||||
* insert loads as soon, stores as late as possible
|
||||
* insert spill insns as outward as possible (either looptree, or LCM)
|
||||
* reuse stack-slots
|
||||
* delete coalesced insns. Partly done. The rest can only go, when we get
|
||||
rid of reload.
|
||||
* don't destroy coalescing information completely when spilling
|
||||
* use the constraints from asms
|
||||
*/
|
||||
|
||||
static int first_hard_reg (HARD_REG_SET);
|
||||
static struct obstack ra_obstack;
|
||||
static void create_insn_info (struct df *);
|
||||
static void free_insn_info (void);
|
||||
static void alloc_mem (struct df *);
|
||||
static void free_mem (struct df *);
|
||||
static void free_all_mem (struct df *df);
|
||||
static int one_pass (struct df *, int);
|
||||
static void check_df (struct df *);
|
||||
static void init_ra (void);
|
||||
|
||||
void reg_alloc (void);
|
||||
|
||||
/* These global variables are "internal" to the register allocator.
|
||||
They are all documented at their declarations in ra.h. */
|
||||
|
||||
/* Somewhen we want to get rid of one of those sbitmaps.
|
||||
(for now I need the sup_igraph to note if there is any conflict between
|
||||
parts of webs at all. I can't use igraph for this, as there only the real
|
||||
conflicts are noted.) This is only used to prevent coalescing two
|
||||
conflicting webs, were only parts of them are in conflict. */
|
||||
sbitmap igraph;
|
||||
sbitmap sup_igraph;
|
||||
|
||||
/* Note the insns not inserted by the allocator, where we detected any
|
||||
deaths of pseudos. It is used to detect closeness of defs and uses.
|
||||
In the first pass this is empty (we could initialize it from REG_DEAD
|
||||
notes), in the other passes it is left from the pass before. */
|
||||
sbitmap insns_with_deaths;
|
||||
int death_insns_max_uid;
|
||||
|
||||
struct web_part *web_parts;
|
||||
|
||||
unsigned int num_webs;
|
||||
unsigned int num_subwebs;
|
||||
unsigned int num_allwebs;
|
||||
struct web **id2web;
|
||||
struct web *hardreg2web[FIRST_PSEUDO_REGISTER];
|
||||
struct web **def2web;
|
||||
struct web **use2web;
|
||||
struct move_list *wl_moves;
|
||||
int ra_max_regno;
|
||||
short *ra_reg_renumber;
|
||||
struct df *df;
|
||||
bitmap *live_at_end;
|
||||
int ra_pass;
|
||||
unsigned int max_normal_pseudo;
|
||||
int an_unusable_color;
|
||||
|
||||
/* The different lists on which a web can be (based on the type). */
|
||||
struct dlist *web_lists[(int) LAST_NODE_TYPE];
|
||||
|
||||
unsigned int last_def_id;
|
||||
unsigned int last_use_id;
|
||||
unsigned int last_num_webs;
|
||||
int last_max_uid;
|
||||
sbitmap last_check_uses;
|
||||
unsigned int remember_conflicts;
|
||||
|
||||
int orig_max_uid;
|
||||
|
||||
HARD_REG_SET never_use_colors;
|
||||
HARD_REG_SET usable_regs[N_REG_CLASSES];
|
||||
unsigned int num_free_regs[N_REG_CLASSES];
|
||||
int single_reg_in_regclass[N_REG_CLASSES];
|
||||
HARD_REG_SET hardregs_for_mode[NUM_MACHINE_MODES];
|
||||
HARD_REG_SET invalid_mode_change_regs;
|
||||
unsigned char byte2bitcount[256];
|
||||
|
||||
unsigned int debug_new_regalloc = -1;
|
||||
int flag_ra_biased = 0;
|
||||
int flag_ra_improved_spilling = 0;
|
||||
int flag_ra_ir_spilling = 0;
|
||||
int flag_ra_optimistic_coalescing = 0;
|
||||
int flag_ra_break_aliases = 0;
|
||||
int flag_ra_merge_spill_costs = 0;
|
||||
int flag_ra_spill_every_use = 0;
|
||||
int flag_ra_dump_notes = 0;
|
||||
|
||||
/* Fast allocation of small objects, which live until the allocator
|
||||
is done. Allocate an object of SIZE bytes. */
|
||||
|
||||
void *
|
||||
ra_alloc (size_t size)
|
||||
{
|
||||
return obstack_alloc (&ra_obstack, size);
|
||||
}
|
||||
|
||||
/* Like ra_alloc(), but clear the returned memory. */
|
||||
|
||||
void *
|
||||
ra_calloc (size_t size)
|
||||
{
|
||||
void *p = obstack_alloc (&ra_obstack, size);
|
||||
memset (p, 0, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Returns the number of hardregs in HARD_REG_SET RS. */
|
||||
|
||||
int
|
||||
hard_regs_count (HARD_REG_SET rs)
|
||||
{
|
||||
int count = 0;
|
||||
#ifdef HARD_REG_SET
|
||||
while (rs)
|
||||
{
|
||||
unsigned char byte = rs & 0xFF;
|
||||
rs >>= 8;
|
||||
/* Avoid memory access, if nothing is set. */
|
||||
if (byte)
|
||||
count += byte2bitcount[byte];
|
||||
}
|
||||
#else
|
||||
unsigned int ofs;
|
||||
for (ofs = 0; ofs < HARD_REG_SET_LONGS; ofs++)
|
||||
{
|
||||
HARD_REG_ELT_TYPE elt = rs[ofs];
|
||||
while (elt)
|
||||
{
|
||||
unsigned char byte = elt & 0xFF;
|
||||
elt >>= 8;
|
||||
if (byte)
|
||||
count += byte2bitcount[byte];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Returns the first hardreg in HARD_REG_SET RS. Assumes there is at
|
||||
least one reg in the set. */
|
||||
|
||||
static int
|
||||
first_hard_reg (HARD_REG_SET rs)
|
||||
{
|
||||
int c;
|
||||
|
||||
for (c = 0; c < FIRST_PSEUDO_REGISTER; c++)
|
||||
if (TEST_HARD_REG_BIT (rs, c))
|
||||
break;
|
||||
gcc_assert (c < FIRST_PSEUDO_REGISTER);
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Basically like emit_move_insn (i.e. validifies constants and such),
|
||||
but also handle MODE_CC moves (but then the operands must already
|
||||
be basically valid. */
|
||||
|
||||
rtx
|
||||
ra_emit_move_insn (rtx x, rtx y)
|
||||
{
|
||||
enum machine_mode mode = GET_MODE (x);
|
||||
if (GET_MODE_CLASS (mode) == MODE_CC)
|
||||
return emit_insn (gen_move_insn (x, y));
|
||||
else
|
||||
return emit_move_insn (x, y);
|
||||
}
|
||||
|
||||
int insn_df_max_uid;
|
||||
struct ra_insn_info *insn_df;
|
||||
static struct ref **refs_for_insn_df;
|
||||
|
||||
/* Create the insn_df structure for each insn to have fast access to
|
||||
all valid defs and uses in an insn. */
|
||||
|
||||
static void
|
||||
create_insn_info (struct df *df)
|
||||
{
|
||||
rtx insn;
|
||||
struct ref **act_refs;
|
||||
insn_df_max_uid = get_max_uid ();
|
||||
insn_df = xcalloc (insn_df_max_uid, sizeof (insn_df[0]));
|
||||
refs_for_insn_df = xcalloc (df->def_id + df->use_id, sizeof (struct ref *));
|
||||
act_refs = refs_for_insn_df;
|
||||
/* We create those things backwards to mimic the order in which
|
||||
the insns are visited in rewrite_program2() and live_in(). */
|
||||
for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
|
||||
{
|
||||
int uid = INSN_UID (insn);
|
||||
unsigned int n;
|
||||
struct df_link *link;
|
||||
if (!INSN_P (insn))
|
||||
continue;
|
||||
for (n = 0, link = DF_INSN_DEFS (df, insn); link; link = link->next)
|
||||
if (link->ref
|
||||
&& (DF_REF_REGNO (link->ref) >= FIRST_PSEUDO_REGISTER
|
||||
|| !TEST_HARD_REG_BIT (never_use_colors,
|
||||
DF_REF_REGNO (link->ref))))
|
||||
{
|
||||
if (n == 0)
|
||||
insn_df[uid].defs = act_refs;
|
||||
insn_df[uid].defs[n++] = link->ref;
|
||||
}
|
||||
act_refs += n;
|
||||
insn_df[uid].num_defs = n;
|
||||
for (n = 0, link = DF_INSN_USES (df, insn); link; link = link->next)
|
||||
if (link->ref
|
||||
&& (DF_REF_REGNO (link->ref) >= FIRST_PSEUDO_REGISTER
|
||||
|| !TEST_HARD_REG_BIT (never_use_colors,
|
||||
DF_REF_REGNO (link->ref))))
|
||||
{
|
||||
if (n == 0)
|
||||
insn_df[uid].uses = act_refs;
|
||||
insn_df[uid].uses[n++] = link->ref;
|
||||
}
|
||||
act_refs += n;
|
||||
insn_df[uid].num_uses = n;
|
||||
}
|
||||
gcc_assert (refs_for_insn_df + (df->def_id + df->use_id) >= act_refs);
|
||||
}
|
||||
|
||||
/* Free the insn_df structures. */
|
||||
|
||||
static void
|
||||
free_insn_info (void)
|
||||
{
|
||||
free (refs_for_insn_df);
|
||||
refs_for_insn_df = NULL;
|
||||
free (insn_df);
|
||||
insn_df = NULL;
|
||||
insn_df_max_uid = 0;
|
||||
}
|
||||
|
||||
/* Search WEB for a subweb, which represents REG. REG needs to
|
||||
be a SUBREG, and the inner reg of it needs to be the one which is
|
||||
represented by WEB. Returns the matching subweb or NULL. */
|
||||
|
||||
struct web *
|
||||
find_subweb (struct web *web, rtx reg)
|
||||
{
|
||||
struct web *w;
|
||||
gcc_assert (GET_CODE (reg) == SUBREG);
|
||||
for (w = web->subreg_next; w; w = w->subreg_next)
|
||||
if (GET_MODE (w->orig_x) == GET_MODE (reg)
|
||||
&& SUBREG_BYTE (w->orig_x) == SUBREG_BYTE (reg))
|
||||
return w;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Similar to find_subweb(), but matches according to SIZE_WORD,
|
||||
a collection of the needed size and offset (in bytes). */
|
||||
|
||||
struct web *
|
||||
find_subweb_2 (struct web *web, unsigned int size_word)
|
||||
{
|
||||
struct web *w = web;
|
||||
if (size_word == GET_MODE_SIZE (GET_MODE (web->orig_x)))
|
||||
/* size_word == size means BYTE_BEGIN(size_word) == 0. */
|
||||
return web;
|
||||
for (w = web->subreg_next; w; w = w->subreg_next)
|
||||
{
|
||||
unsigned int bl = rtx_to_bits (w->orig_x);
|
||||
if (size_word == bl)
|
||||
return w;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returns the superweb for SUBWEB. */
|
||||
|
||||
struct web *
|
||||
find_web_for_subweb_1 (struct web *subweb)
|
||||
{
|
||||
while (subweb->parent_web)
|
||||
subweb = subweb->parent_web;
|
||||
return subweb;
|
||||
}
|
||||
|
||||
/* Determine if two hard register sets intersect.
|
||||
Return 1 if they do. */
|
||||
|
||||
int
|
||||
hard_regs_intersect_p (HARD_REG_SET *a, HARD_REG_SET *b)
|
||||
{
|
||||
HARD_REG_SET c;
|
||||
COPY_HARD_REG_SET (c, *a);
|
||||
AND_HARD_REG_SET (c, *b);
|
||||
GO_IF_HARD_REG_SUBSET (c, reg_class_contents[(int) NO_REGS], lose);
|
||||
return 1;
|
||||
lose:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate and initialize the memory necessary for one pass of the
|
||||
register allocator. */
|
||||
|
||||
static void
|
||||
alloc_mem (struct df *df)
|
||||
{
|
||||
int i;
|
||||
ra_build_realloc (df);
|
||||
if (!live_at_end)
|
||||
{
|
||||
live_at_end = xmalloc ((last_basic_block + 2) * sizeof (bitmap));
|
||||
for (i = 0; i < last_basic_block + 2; i++)
|
||||
live_at_end[i] = BITMAP_XMALLOC ();
|
||||
live_at_end += 2;
|
||||
}
|
||||
create_insn_info (df);
|
||||
}
|
||||
|
||||
/* Free the memory which isn't necessary for the next pass. */
|
||||
|
||||
static void
|
||||
free_mem (struct df *df ATTRIBUTE_UNUSED)
|
||||
{
|
||||
free_insn_info ();
|
||||
ra_build_free ();
|
||||
}
|
||||
|
||||
/* Free all memory allocated for the register allocator. Used, when
|
||||
it's done. */
|
||||
|
||||
static void
|
||||
free_all_mem (struct df *df)
|
||||
{
|
||||
unsigned int i;
|
||||
live_at_end -= 2;
|
||||
for (i = 0; i < (unsigned)last_basic_block + 2; i++)
|
||||
BITMAP_XFREE (live_at_end[i]);
|
||||
free (live_at_end);
|
||||
|
||||
ra_colorize_free_all ();
|
||||
ra_build_free_all (df);
|
||||
obstack_free (&ra_obstack, NULL);
|
||||
}
|
||||
|
||||
static long ticks_build;
|
||||
static long ticks_rebuild;
|
||||
|
||||
/* Perform one pass of allocation. Returns nonzero, if some spill code
|
||||
was added, i.e. if the allocator needs to rerun. */
|
||||
|
||||
static int
|
||||
one_pass (struct df *df, int rebuild)
|
||||
{
|
||||
long ticks = clock ();
|
||||
int something_spilled;
|
||||
remember_conflicts = 0;
|
||||
|
||||
/* Build the complete interference graph, or if this is not the first
|
||||
pass, rebuild it incrementally. */
|
||||
build_i_graph (df);
|
||||
|
||||
/* From now on, if we create new conflicts, we need to remember the
|
||||
initial list of conflicts per web. */
|
||||
remember_conflicts = 1;
|
||||
if (!rebuild)
|
||||
dump_igraph_machine ();
|
||||
|
||||
/* Colorize the I-graph. This results in either a list of
|
||||
spilled_webs, in which case we need to run the spill phase, and
|
||||
rerun the allocator, or that list is empty, meaning we are done. */
|
||||
ra_colorize_graph (df);
|
||||
|
||||
last_max_uid = get_max_uid ();
|
||||
/* actual_spill() might change WEBS(SPILLED) and even empty it,
|
||||
so we need to remember it's state. */
|
||||
something_spilled = !!WEBS(SPILLED);
|
||||
|
||||
/* Add spill code if necessary. */
|
||||
if (something_spilled)
|
||||
actual_spill ();
|
||||
|
||||
ticks = clock () - ticks;
|
||||
if (rebuild)
|
||||
ticks_rebuild += ticks;
|
||||
else
|
||||
ticks_build += ticks;
|
||||
return something_spilled;
|
||||
}
|
||||
|
||||
/* Initialize various arrays for the register allocator. */
|
||||
|
||||
static void
|
||||
init_ra (void)
|
||||
{
|
||||
int i;
|
||||
HARD_REG_SET rs;
|
||||
#ifdef ELIMINABLE_REGS
|
||||
static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS;
|
||||
unsigned int j;
|
||||
#endif
|
||||
int need_fp
|
||||
= (! flag_omit_frame_pointer
|
||||
|| (current_function_calls_alloca && EXIT_IGNORE_STACK)
|
||||
|| FRAME_POINTER_REQUIRED);
|
||||
|
||||
ra_colorize_init ();
|
||||
|
||||
/* We can't ever use any of the fixed regs. */
|
||||
COPY_HARD_REG_SET (never_use_colors, fixed_reg_set);
|
||||
|
||||
/* Additionally don't even try to use hardregs, which we already
|
||||
know are not eliminable. This includes also either the
|
||||
hard framepointer or all regs which are eliminable into the
|
||||
stack pointer, if need_fp is set. */
|
||||
#ifdef ELIMINABLE_REGS
|
||||
for (j = 0; j < ARRAY_SIZE (eliminables); j++)
|
||||
{
|
||||
if (! CAN_ELIMINATE (eliminables[j].from, eliminables[j].to)
|
||||
|| (eliminables[j].to == STACK_POINTER_REGNUM && need_fp))
|
||||
for (i = hard_regno_nregs[eliminables[j].from][Pmode]; i--;)
|
||||
SET_HARD_REG_BIT (never_use_colors, eliminables[j].from + i);
|
||||
}
|
||||
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
|
||||
if (need_fp)
|
||||
for (i = hard_regno_nregs[HARD_FRAME_POINTER_REGNUM][Pmode]; i--;)
|
||||
SET_HARD_REG_BIT (never_use_colors, HARD_FRAME_POINTER_REGNUM + i);
|
||||
#endif
|
||||
|
||||
#else
|
||||
if (need_fp)
|
||||
for (i = hard_regno_nregs[FRAME_POINTER_REGNUM][Pmode]; i--;)
|
||||
SET_HARD_REG_BIT (never_use_colors, FRAME_POINTER_REGNUM + i);
|
||||
#endif
|
||||
|
||||
/* Stack and argument pointer are also rather useless to us. */
|
||||
for (i = hard_regno_nregs[STACK_POINTER_REGNUM][Pmode]; i--;)
|
||||
SET_HARD_REG_BIT (never_use_colors, STACK_POINTER_REGNUM + i);
|
||||
|
||||
for (i = hard_regno_nregs[ARG_POINTER_REGNUM][Pmode]; i--;)
|
||||
SET_HARD_REG_BIT (never_use_colors, ARG_POINTER_REGNUM + i);
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
unsigned char byte = ((unsigned) i) & 0xFF;
|
||||
unsigned char count = 0;
|
||||
while (byte)
|
||||
{
|
||||
if (byte & 1)
|
||||
count++;
|
||||
byte >>= 1;
|
||||
}
|
||||
byte2bitcount[i] = count;
|
||||
}
|
||||
|
||||
for (i = 0; i < N_REG_CLASSES; i++)
|
||||
{
|
||||
int size;
|
||||
COPY_HARD_REG_SET (rs, reg_class_contents[i]);
|
||||
AND_COMPL_HARD_REG_SET (rs, never_use_colors);
|
||||
size = hard_regs_count (rs);
|
||||
num_free_regs[i] = size;
|
||||
COPY_HARD_REG_SET (usable_regs[i], rs);
|
||||
if (size == 1)
|
||||
single_reg_in_regclass[i] = first_hard_reg (rs);
|
||||
else
|
||||
single_reg_in_regclass[i] = -1;
|
||||
}
|
||||
|
||||
/* Setup hardregs_for_mode[].
|
||||
We are not interested only in the beginning of a multi-reg, but in
|
||||
all the hardregs involved. Maybe HARD_REGNO_MODE_OK() only ok's
|
||||
for beginnings. */
|
||||
for (i = 0; i < NUM_MACHINE_MODES; i++)
|
||||
{
|
||||
int reg, size;
|
||||
CLEAR_HARD_REG_SET (rs);
|
||||
for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++)
|
||||
if (HARD_REGNO_MODE_OK (reg, i)
|
||||
/* Ignore VOIDmode and similar things. */
|
||||
&& (size = hard_regno_nregs[reg][i]) != 0
|
||||
&& (reg + size) <= FIRST_PSEUDO_REGISTER)
|
||||
{
|
||||
while (size--)
|
||||
SET_HARD_REG_BIT (rs, reg + size);
|
||||
}
|
||||
COPY_HARD_REG_SET (hardregs_for_mode[i], rs);
|
||||
}
|
||||
|
||||
CLEAR_HARD_REG_SET (invalid_mode_change_regs);
|
||||
#ifdef CANNOT_CHANGE_MODE_CLASS
|
||||
if (0)
|
||||
for (i = 0; i < NUM_MACHINE_MODES; i++)
|
||||
{
|
||||
enum machine_mode from = (enum machine_mode) i;
|
||||
enum machine_mode to;
|
||||
for (to = VOIDmode; to < MAX_MACHINE_MODE; ++to)
|
||||
{
|
||||
int r;
|
||||
for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
|
||||
if (REG_CANNOT_CHANGE_MODE_P (from, to, r))
|
||||
SET_HARD_REG_BIT (invalid_mode_change_regs, r);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (an_unusable_color = 0; an_unusable_color < FIRST_PSEUDO_REGISTER;
|
||||
an_unusable_color++)
|
||||
if (TEST_HARD_REG_BIT (never_use_colors, an_unusable_color))
|
||||
break;
|
||||
gcc_assert (an_unusable_color != FIRST_PSEUDO_REGISTER);
|
||||
|
||||
orig_max_uid = get_max_uid ();
|
||||
compute_bb_for_insn ();
|
||||
ra_reg_renumber = NULL;
|
||||
insns_with_deaths = sbitmap_alloc (orig_max_uid);
|
||||
death_insns_max_uid = orig_max_uid;
|
||||
sbitmap_ones (insns_with_deaths);
|
||||
gcc_obstack_init (&ra_obstack);
|
||||
}
|
||||
|
||||
/* Check the consistency of DF. This asserts if it violates some
|
||||
invariances we expect. */
|
||||
|
||||
static void
|
||||
check_df (struct df *df)
|
||||
{
|
||||
struct df_link *link;
|
||||
rtx insn;
|
||||
int regno;
|
||||
unsigned int ui;
|
||||
bitmap b = BITMAP_XMALLOC ();
|
||||
bitmap empty_defs = BITMAP_XMALLOC ();
|
||||
bitmap empty_uses = BITMAP_XMALLOC ();
|
||||
|
||||
/* Collect all the IDs of NULL references in the ID->REF arrays,
|
||||
as df.c leaves them when updating the df structure. */
|
||||
for (ui = 0; ui < df->def_id; ui++)
|
||||
if (!df->defs[ui])
|
||||
bitmap_set_bit (empty_defs, ui);
|
||||
for (ui = 0; ui < df->use_id; ui++)
|
||||
if (!df->uses[ui])
|
||||
bitmap_set_bit (empty_uses, ui);
|
||||
|
||||
/* For each insn we check if the chain of references contain each
|
||||
ref only once, doesn't contain NULL refs, or refs whose ID is invalid
|
||||
(it df->refs[id] element is NULL). */
|
||||
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||
if (INSN_P (insn))
|
||||
{
|
||||
bitmap_clear (b);
|
||||
for (link = DF_INSN_DEFS (df, insn); link; link = link->next)
|
||||
{
|
||||
gcc_assert (link->ref);
|
||||
gcc_assert (!bitmap_bit_p (empty_defs, DF_REF_ID (link->ref)));
|
||||
gcc_assert (!bitmap_bit_p (b, DF_REF_ID (link->ref)));
|
||||
bitmap_set_bit (b, DF_REF_ID (link->ref));
|
||||
}
|
||||
|
||||
bitmap_clear (b);
|
||||
for (link = DF_INSN_USES (df, insn); link; link = link->next)
|
||||
{
|
||||
gcc_assert (link->ref);
|
||||
gcc_assert (!bitmap_bit_p (empty_uses, DF_REF_ID (link->ref)));
|
||||
gcc_assert (!bitmap_bit_p (b, DF_REF_ID (link->ref)));
|
||||
bitmap_set_bit (b, DF_REF_ID (link->ref));
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the same for the chains per register number. */
|
||||
for (regno = 0; regno < max_reg_num (); regno++)
|
||||
{
|
||||
bitmap_clear (b);
|
||||
for (link = df->regs[regno].defs; link; link = link->next)
|
||||
{
|
||||
gcc_assert (link->ref);
|
||||
gcc_assert (!bitmap_bit_p (empty_defs, DF_REF_ID (link->ref)));
|
||||
gcc_assert (!bitmap_bit_p (b, DF_REF_ID (link->ref)));
|
||||
bitmap_set_bit (b, DF_REF_ID (link->ref));
|
||||
}
|
||||
|
||||
bitmap_clear (b);
|
||||
for (link = df->regs[regno].uses; link; link = link->next)
|
||||
{
|
||||
gcc_assert (link->ref);
|
||||
gcc_assert (!bitmap_bit_p (empty_uses, DF_REF_ID (link->ref)));
|
||||
gcc_assert (!bitmap_bit_p (b, DF_REF_ID (link->ref)));
|
||||
bitmap_set_bit (b, DF_REF_ID (link->ref));
|
||||
}
|
||||
}
|
||||
|
||||
BITMAP_XFREE (empty_uses);
|
||||
BITMAP_XFREE (empty_defs);
|
||||
BITMAP_XFREE (b);
|
||||
}
|
||||
|
||||
/* Main register allocator entry point. */
|
||||
|
||||
void
|
||||
reg_alloc (void)
|
||||
{
|
||||
int changed;
|
||||
FILE *ra_dump_file = dump_file;
|
||||
rtx last = get_last_insn ();
|
||||
|
||||
if (! INSN_P (last))
|
||||
last = prev_real_insn (last);
|
||||
/* If this is an empty function we shouldn't do all the following,
|
||||
but instead just setup what's necessary, and return. */
|
||||
|
||||
/* We currently rely on the existence of the return value USE as
|
||||
one of the last insns. Add it if it's not there anymore. */
|
||||
if (last)
|
||||
{
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
|
||||
FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
|
||||
{
|
||||
basic_block bb = e->src;
|
||||
last = BB_END (bb);
|
||||
if (!INSN_P (last) || GET_CODE (PATTERN (last)) != USE)
|
||||
{
|
||||
rtx insns;
|
||||
start_sequence ();
|
||||
use_return_register ();
|
||||
insns = get_insns ();
|
||||
end_sequence ();
|
||||
emit_insn_after (insns, last);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup debugging levels. */
|
||||
switch (0)
|
||||
{
|
||||
/* Some useful presets of the debug level, I often use. */
|
||||
case 0: debug_new_regalloc = DUMP_EVER; break;
|
||||
case 1: debug_new_regalloc = DUMP_COSTS; break;
|
||||
case 2: debug_new_regalloc = DUMP_IGRAPH_M; break;
|
||||
case 3: debug_new_regalloc = DUMP_COLORIZE + DUMP_COSTS; break;
|
||||
case 4: debug_new_regalloc = DUMP_COLORIZE + DUMP_COSTS + DUMP_WEBS;
|
||||
break;
|
||||
case 5: debug_new_regalloc = DUMP_FINAL_RTL + DUMP_COSTS +
|
||||
DUMP_CONSTRAINTS;
|
||||
break;
|
||||
case 6: debug_new_regalloc = DUMP_VALIDIFY; break;
|
||||
}
|
||||
if (!dump_file)
|
||||
debug_new_regalloc = 0;
|
||||
|
||||
/* Run regclass first, so we know the preferred and alternate classes
|
||||
for each pseudo. Deactivate emitting of debug info, if it's not
|
||||
explicitly requested. */
|
||||
if ((debug_new_regalloc & DUMP_REGCLASS) == 0)
|
||||
dump_file = NULL;
|
||||
regclass (get_insns (), max_reg_num (), dump_file);
|
||||
dump_file = ra_dump_file;
|
||||
|
||||
/* We don't use those NOTEs, and as we anyway change all registers,
|
||||
they only make problems later. */
|
||||
count_or_remove_death_notes (NULL, 1);
|
||||
|
||||
/* Initialize the different global arrays and regsets. */
|
||||
init_ra ();
|
||||
|
||||
/* And some global variables. */
|
||||
ra_pass = 0;
|
||||
no_new_pseudos = 0;
|
||||
max_normal_pseudo = (unsigned) max_reg_num ();
|
||||
ra_rewrite_init ();
|
||||
last_def_id = 0;
|
||||
last_use_id = 0;
|
||||
last_num_webs = 0;
|
||||
last_max_uid = 0;
|
||||
last_check_uses = NULL;
|
||||
live_at_end = NULL;
|
||||
WEBS(INITIAL) = NULL;
|
||||
WEBS(FREE) = NULL;
|
||||
memset (hardreg2web, 0, sizeof (hardreg2web));
|
||||
ticks_build = ticks_rebuild = 0;
|
||||
|
||||
/* The default is to use optimistic coalescing with interference
|
||||
region spilling, without biased coloring. */
|
||||
flag_ra_biased = 0;
|
||||
flag_ra_spill_every_use = 0;
|
||||
flag_ra_improved_spilling = 1;
|
||||
flag_ra_ir_spilling = 1;
|
||||
flag_ra_break_aliases = 0;
|
||||
flag_ra_optimistic_coalescing = 1;
|
||||
flag_ra_merge_spill_costs = 1;
|
||||
if (flag_ra_optimistic_coalescing)
|
||||
flag_ra_break_aliases = 1;
|
||||
flag_ra_dump_notes = 0;
|
||||
|
||||
/* Allocate the global df structure. */
|
||||
df = df_init ();
|
||||
|
||||
/* This is the main loop, calling one_pass as long as there are still
|
||||
some spilled webs. */
|
||||
do
|
||||
{
|
||||
ra_debug_msg (DUMP_NEARLY_EVER, "RegAlloc Pass %d\n\n", ra_pass);
|
||||
if (ra_pass++ > 40)
|
||||
internal_error ("Didn't find a coloring.\n");
|
||||
|
||||
/* First collect all the register refs and put them into
|
||||
chains per insn, and per regno. In later passes only update
|
||||
that info from the new and modified insns. */
|
||||
df_analyze (df, (ra_pass == 1) ? 0 : (bitmap) -1,
|
||||
DF_HARD_REGS | DF_RD_CHAIN | DF_RU_CHAIN | DF_FOR_REGALLOC);
|
||||
|
||||
if ((debug_new_regalloc & DUMP_DF) != 0)
|
||||
{
|
||||
rtx insn;
|
||||
df_dump (df, DF_HARD_REGS, dump_file);
|
||||
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||
if (INSN_P (insn))
|
||||
df_insn_debug_regno (df, insn, dump_file);
|
||||
}
|
||||
check_df (df);
|
||||
|
||||
/* Now allocate the memory needed for this pass, or (if it's not the
|
||||
first pass), reallocate only additional memory. */
|
||||
alloc_mem (df);
|
||||
|
||||
/* Build and colorize the interference graph, and possibly emit
|
||||
spill insns. This also might delete certain move insns. */
|
||||
changed = one_pass (df, ra_pass > 1);
|
||||
|
||||
/* If that produced no changes, the graph was colorizable. */
|
||||
if (!changed)
|
||||
{
|
||||
/* Change the insns to refer to the new pseudos (one per web). */
|
||||
emit_colors (df);
|
||||
/* Already setup a preliminary reg_renumber[] array, but don't
|
||||
free our own version. reg_renumber[] will again be destroyed
|
||||
later. We right now need it in dump_constraints() for
|
||||
constrain_operands(1) whose subproc sometimes reference
|
||||
it (because we are checking strictly, i.e. as if
|
||||
after reload). */
|
||||
setup_renumber (0);
|
||||
/* Delete some more of the coalesced moves. */
|
||||
delete_moves ();
|
||||
dump_constraints ();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If there were changes, this means spill code was added,
|
||||
therefore repeat some things, including some initialization
|
||||
of global data structures. */
|
||||
if ((debug_new_regalloc & DUMP_REGCLASS) == 0)
|
||||
dump_file = NULL;
|
||||
/* We have new pseudos (the stackwebs). */
|
||||
allocate_reg_info (max_reg_num (), FALSE, FALSE);
|
||||
/* And new insns. */
|
||||
compute_bb_for_insn ();
|
||||
/* Some of them might be dead. */
|
||||
delete_trivially_dead_insns (get_insns (), max_reg_num ());
|
||||
/* Those new pseudos need to have their REFS count set. */
|
||||
reg_scan_update (get_insns (), NULL, max_regno);
|
||||
max_regno = max_reg_num ();
|
||||
/* And they need useful classes too. */
|
||||
regclass (get_insns (), max_reg_num (), dump_file);
|
||||
dump_file = ra_dump_file;
|
||||
|
||||
/* Remember the number of defs and uses, so we can distinguish
|
||||
new from old refs in the next pass. */
|
||||
last_def_id = df->def_id;
|
||||
last_use_id = df->use_id;
|
||||
}
|
||||
|
||||
/* Output the graph, and possibly the current insn sequence. */
|
||||
dump_ra (df);
|
||||
if (changed && (debug_new_regalloc & DUMP_RTL) != 0)
|
||||
{
|
||||
ra_print_rtl_with_bb (dump_file, get_insns ());
|
||||
fflush (dump_file);
|
||||
}
|
||||
|
||||
/* Reset the web lists. */
|
||||
reset_lists ();
|
||||
free_mem (df);
|
||||
}
|
||||
while (changed);
|
||||
|
||||
/* We are done with allocation, free all memory and output some
|
||||
debug info. */
|
||||
free_all_mem (df);
|
||||
df_finish (df);
|
||||
if ((debug_new_regalloc & DUMP_RESULTS) == 0)
|
||||
dump_cost (DUMP_COSTS);
|
||||
ra_debug_msg (DUMP_COSTS, "ticks for build-phase: %ld\n", ticks_build);
|
||||
ra_debug_msg (DUMP_COSTS, "ticks for rebuild-phase: %ld\n", ticks_rebuild);
|
||||
if ((debug_new_regalloc & (DUMP_FINAL_RTL | DUMP_RTL)) != 0)
|
||||
ra_print_rtl_with_bb (dump_file, get_insns ());
|
||||
|
||||
/* We might have new pseudos, so allocate the info arrays for them. */
|
||||
if ((debug_new_regalloc & DUMP_SM) == 0)
|
||||
dump_file = NULL;
|
||||
no_new_pseudos = 0;
|
||||
allocate_reg_info (max_reg_num (), FALSE, FALSE);
|
||||
no_new_pseudos = 1;
|
||||
dump_file = ra_dump_file;
|
||||
|
||||
/* Some spill insns could've been inserted after trapping calls, i.e.
|
||||
at the end of a basic block, which really ends at that call.
|
||||
Fixup that breakages by adjusting basic block boundaries. */
|
||||
fixup_abnormal_edges ();
|
||||
|
||||
/* Cleanup the flow graph. */
|
||||
if ((debug_new_regalloc & DUMP_LAST_FLOW) == 0)
|
||||
dump_file = NULL;
|
||||
life_analysis (dump_file,
|
||||
PROP_DEATH_NOTES | PROP_LOG_LINKS | PROP_REG_INFO);
|
||||
cleanup_cfg (CLEANUP_EXPENSIVE);
|
||||
recompute_reg_usage (get_insns (), TRUE);
|
||||
if (dump_file)
|
||||
dump_flow_info (dump_file);
|
||||
dump_file = ra_dump_file;
|
||||
|
||||
/* update_equiv_regs() can't be called after register allocation.
|
||||
It might delete some pseudos, and insert other insns setting
|
||||
up those pseudos in different places. This of course screws up
|
||||
the allocation because that may destroy a hardreg for another
|
||||
pseudo.
|
||||
XXX we probably should do something like that on our own. I.e.
|
||||
creating REG_EQUIV notes. */
|
||||
/*update_equiv_regs ();*/
|
||||
|
||||
/* Setup the reg_renumber[] array for reload. */
|
||||
setup_renumber (1);
|
||||
sbitmap_free (insns_with_deaths);
|
||||
|
||||
/* Remove REG_DEAD notes which are incorrectly set. See the docu
|
||||
of that function. */
|
||||
remove_suspicious_death_notes ();
|
||||
|
||||
if ((debug_new_regalloc & DUMP_LAST_RTL) != 0)
|
||||
ra_print_rtl_with_bb (dump_file, get_insns ());
|
||||
dump_static_insn_cost (dump_file,
|
||||
"after allocation/spilling, before reload", NULL);
|
||||
|
||||
/* Allocate the reg_equiv_memory_loc array for reload. */
|
||||
VARRAY_GROW (reg_equiv_memory_loc_varray, max_regno);
|
||||
reg_equiv_memory_loc = &VARRAY_RTX (reg_equiv_memory_loc_varray, 0);
|
||||
/* And possibly initialize it. */
|
||||
allocate_initial_values (reg_equiv_memory_loc);
|
||||
/* And one last regclass pass just before reload. */
|
||||
regclass (get_insns (), max_reg_num (), dump_file);
|
||||
}
|
||||
|
||||
/*
|
||||
vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4:
|
||||
*/
|
642
gcc/ra.h
642
gcc/ra.h
@ -1,642 +0,0 @@
|
||||
/* Graph coloring register allocator
|
||||
Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||
Contributed by Michael Matz <matz@suse.de>
|
||||
and Daniel Berlin <dan@cgsoftware.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 2, or (at your option) any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with GCC; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef GCC_RA_H
|
||||
#define GCC_RA_H
|
||||
|
||||
#include "bitmap.h"
|
||||
#include "sbitmap.h"
|
||||
#include "hard-reg-set.h"
|
||||
#include "insn-modes.h"
|
||||
|
||||
/* Double linked list to implement the per-type lists of webs
|
||||
and moves. */
|
||||
struct dlist
|
||||
{
|
||||
struct dlist *prev;
|
||||
struct dlist *next;
|
||||
union
|
||||
{
|
||||
struct web *web;
|
||||
struct move *move;
|
||||
} value;
|
||||
};
|
||||
/* Simple helper macros for ease of misuse. */
|
||||
#define DLIST_WEB(l) ((l)->value.web)
|
||||
#define DLIST_MOVE(l) ((l)->value.move)
|
||||
|
||||
/* Classification of a given node (i.e. what state it's in). */
|
||||
enum ra_node_type
|
||||
{
|
||||
INITIAL = 0, FREE,
|
||||
PRECOLORED,
|
||||
SIMPLIFY, SIMPLIFY_SPILL, SIMPLIFY_FAT, FREEZE, SPILL,
|
||||
SELECT,
|
||||
SPILLED, COALESCED, COLORED,
|
||||
LAST_NODE_TYPE
|
||||
};
|
||||
|
||||
/* A list of conflict bitmaps, factorized on the exact part of
|
||||
the source, which conflicts with the DEFs, whose ID are noted in
|
||||
the bitmap. This is used while building web-parts with conflicts. */
|
||||
struct tagged_conflict
|
||||
{
|
||||
struct tagged_conflict *next;
|
||||
bitmap conflicts;
|
||||
|
||||
/* If the part of source identified by size S, byteoffset O conflicts,
|
||||
then size_word == S | (O << 16). */
|
||||
unsigned int size_word;
|
||||
};
|
||||
|
||||
/* Such a structure is allocated initially for each def and use.
|
||||
In the process of building the interference graph web parts are
|
||||
connected together, if they have common instructions and reference the
|
||||
same register. That way live ranges are build (by connecting defs and
|
||||
uses) and implicitly complete webs (by connecting web parts in common
|
||||
uses). */
|
||||
struct web_part
|
||||
{
|
||||
/* The def or use for this web part. */
|
||||
struct ref *ref;
|
||||
/* The uplink implementing the disjoint set. */
|
||||
struct web_part *uplink;
|
||||
|
||||
/* Here dynamic information associated with each def/use is saved.
|
||||
This all is only valid for root web parts (uplink==NULL).
|
||||
That's the information we need to merge, if web parts are unioned. */
|
||||
|
||||
/* Number of spanned insns containing any deaths. */
|
||||
unsigned int spanned_deaths;
|
||||
/* The list of bitmaps of DEF ID's with which this part conflicts. */
|
||||
struct tagged_conflict *sub_conflicts;
|
||||
/* If there's any call_insn, while this part is live. */
|
||||
unsigned int crosses_call : 1;
|
||||
};
|
||||
|
||||
/* Web structure used to store info about connected live ranges.
|
||||
This represents the nodes of the interference graph, which gets
|
||||
colored. It can also hold subwebs, which are contained in webs
|
||||
and represent subregs. */
|
||||
struct web
|
||||
{
|
||||
/* Unique web ID. */
|
||||
unsigned int id;
|
||||
|
||||
/* Register number of the live range's variable. */
|
||||
unsigned int regno;
|
||||
|
||||
/* How many insns containing deaths do we span? */
|
||||
unsigned int span_deaths;
|
||||
|
||||
/* Spill_temp indicates if this web was part of a web spilled in the
|
||||
last iteration, or or reasons why this shouldn't be spilled again.
|
||||
1 spill web, can't be spilled.
|
||||
2 big spill web (live over some deaths). Discouraged, but not
|
||||
impossible to spill again.
|
||||
3 short web (spans no deaths), can't be spilled. */
|
||||
unsigned int spill_temp;
|
||||
|
||||
/* When coalescing we might change spill_temp. If breaking aliases we
|
||||
need to restore it. */
|
||||
unsigned int orig_spill_temp;
|
||||
|
||||
/* Cost of spilling. */
|
||||
unsigned HOST_WIDE_INT spill_cost;
|
||||
unsigned HOST_WIDE_INT orig_spill_cost;
|
||||
|
||||
/* How many webs are aliased to us? */
|
||||
unsigned int num_aliased;
|
||||
|
||||
/* The color we got. This is a hardreg number. */
|
||||
int color;
|
||||
/* 1 + the color this web got in the last pass. If it hadn't got a color,
|
||||
or we are in the first pass, or this web is a new one, this is zero. */
|
||||
int old_color;
|
||||
|
||||
/* Now follow some flags characterizing the web. */
|
||||
|
||||
/* Nonzero, if we should use usable_regs for this web, instead of
|
||||
preferred_class() or alternate_class(). */
|
||||
unsigned int use_my_regs:1;
|
||||
|
||||
/* Nonzero if we selected this web as possible spill candidate in
|
||||
select_spill(). */
|
||||
unsigned int was_spilled:1;
|
||||
|
||||
/* We need to distinguish also webs which are targets of coalescing
|
||||
(all x with some y, so that x==alias(y)), but the alias field is
|
||||
only set for sources of coalescing. This flag is set for all webs
|
||||
involved in coalescing in some way. */
|
||||
unsigned int is_coalesced:1;
|
||||
|
||||
/* Nonzero, if this web (or subweb) doesn't correspond with any of
|
||||
the current functions actual use of reg rtx. Happens e.g. with
|
||||
conflicts to a web, of which only a part was still undefined at the
|
||||
point of that conflict. In this case we construct a subweb
|
||||
representing these yet undefined bits to have a target for the
|
||||
conflict. Suppose e.g. this sequence:
|
||||
(set (reg:DI x) ...)
|
||||
(set (reg:SI y) ...)
|
||||
(set (subreg:SI (reg:DI x) 0) ...)
|
||||
(use (reg:DI x))
|
||||
Here x only partly conflicts with y. Namely only (subreg:SI (reg:DI x)
|
||||
1) conflicts with it, but this rtx doesn't show up in the program. For
|
||||
such things an "artificial" subweb is built, and this flag is true for
|
||||
them. */
|
||||
unsigned int artificial:1;
|
||||
|
||||
/* Nonzero if we span a call_insn. */
|
||||
unsigned int crosses_call:1;
|
||||
|
||||
/* Wether the web is involved in a move insn. */
|
||||
unsigned int move_related:1;
|
||||
|
||||
/* 1 when this web (or parts thereof) are live over an abnormal edge. */
|
||||
unsigned int live_over_abnormal:1;
|
||||
|
||||
/* Nonzero if this web is used in subregs where the mode change
|
||||
was illegal for hardregs in CLASS_CANNOT_CHANGE_MODE. */
|
||||
unsigned int mode_changed:1;
|
||||
|
||||
/* Nonzero if some references of this web, where in subreg context,
|
||||
but the actual subreg is already stripped (i.e. we don't know the
|
||||
outer mode of the actual reference). */
|
||||
unsigned int subreg_stripped:1;
|
||||
|
||||
/* Nonzero, when this web stems from the last pass of the allocator,
|
||||
and all info is still valid (i.e. it wasn't spilled). */
|
||||
unsigned int old_web:1;
|
||||
|
||||
/* Used in rewrite_program2() to remember webs, which
|
||||
are already marked for (re)loading. */
|
||||
unsigned int in_load:1;
|
||||
|
||||
/* If in_load is != 0, then this is nonzero, if only one use was seen
|
||||
since insertion in loadlist. Zero if more uses currently need a
|
||||
reload. Used to differentiate between inserting register loads or
|
||||
directly substituting the stackref. */
|
||||
unsigned int one_load:1;
|
||||
|
||||
/* When using rewrite_program2() this flag gets set if some insns
|
||||
were inserted on behalf of this web. IR spilling might ignore some
|
||||
deaths up to the def, so no code might be emitted and we need not to
|
||||
spill such a web again. */
|
||||
unsigned int changed:1;
|
||||
|
||||
/* With interference region spilling it's sometimes the case, that a
|
||||
bb border is also an IR border for webs, which were targets of moves,
|
||||
which are already removed due to coalescing. All webs, which are
|
||||
a destination of such a removed move, have this flag set. */
|
||||
unsigned int target_of_spilled_move:1;
|
||||
|
||||
/* For optimistic coalescing we need to be able to break aliases, which
|
||||
includes restoring conflicts to those before coalescing. This flag
|
||||
is set, if we have a list of conflicts before coalescing. It's needed
|
||||
because that list is lazily constructed only when actually needed. */
|
||||
unsigned int have_orig_conflicts:1;
|
||||
|
||||
/* Current state of the node. */
|
||||
ENUM_BITFIELD(ra_node_type) type:5;
|
||||
|
||||
/* A regclass, combined from preferred and alternate class, or calculated
|
||||
from usable_regs. Used only for debugging, and to determine
|
||||
add_hardregs. */
|
||||
ENUM_BITFIELD(reg_class) regclass:10;
|
||||
|
||||
/* Additional consecutive hardregs needed for this web. */
|
||||
int add_hardregs;
|
||||
|
||||
/* Number of conflicts currently. */
|
||||
int num_conflicts;
|
||||
|
||||
/* Numbers of uses and defs, which belong to this web. */
|
||||
unsigned int num_uses;
|
||||
unsigned int num_defs;
|
||||
|
||||
/* The (reg:M a) or (subreg:M1 (reg:M2 a) x) rtx which this
|
||||
web is based on. This is used to distinguish subreg webs
|
||||
from it's reg parents, and to get hold of the mode. */
|
||||
rtx orig_x;
|
||||
|
||||
/* If this web is a subweb, this point to the super web. Otherwise
|
||||
it's NULL. */
|
||||
struct web *parent_web;
|
||||
|
||||
/* If this web is a subweb, but not the last one, this points to the
|
||||
next subweb of the same super web. Otherwise it's NULL. */
|
||||
struct web *subreg_next;
|
||||
|
||||
/* The set of webs (or subwebs), this web conflicts with. */
|
||||
struct conflict_link *conflict_list;
|
||||
|
||||
/* If have_orig_conflicts is set this contains a copy of conflict_list,
|
||||
as it was right after building the interference graph.
|
||||
It's used for incremental i-graph building and for breaking
|
||||
coalescings again. */
|
||||
struct conflict_link *orig_conflict_list;
|
||||
|
||||
/* Bitmap of all conflicts which don't count this pass, because of
|
||||
non-intersecting hardregs of the conflicting webs. See also
|
||||
record_conflict(). */
|
||||
bitmap useless_conflicts;
|
||||
|
||||
/* Different sets of hard registers, for all usable registers, ... */
|
||||
HARD_REG_SET usable_regs;
|
||||
/* ... the same before coalescing, ... */
|
||||
HARD_REG_SET orig_usable_regs;
|
||||
/* ... colors of all already colored neighbors (used when biased coloring
|
||||
is active), and ... */
|
||||
HARD_REG_SET bias_colors;
|
||||
/* ... colors of PRECOLORED webs this web is connected to by a move. */
|
||||
HARD_REG_SET prefer_colors;
|
||||
|
||||
/* Number of usable colors in usable_regs. */
|
||||
int num_freedom;
|
||||
|
||||
/* After successful coloring the graph each web gets a new reg rtx,
|
||||
with which the original uses and defs are replaced. This is it. */
|
||||
rtx reg_rtx;
|
||||
|
||||
/* While spilling this is the rtx of the home of spilled webs.
|
||||
It can be a mem ref (a stack slot), or a pseudo register. */
|
||||
rtx stack_slot;
|
||||
|
||||
/* Used in rewrite_program2() to remember the using
|
||||
insn last seen for webs needing (re)loads. */
|
||||
rtx last_use_insn;
|
||||
|
||||
/* If this web is rematerializable, this contains the RTL pattern
|
||||
usable as source for that. Otherwise it's NULL. */
|
||||
rtx pattern;
|
||||
|
||||
/* All the defs and uses. There are num_defs, resp.
|
||||
num_uses elements. */
|
||||
struct ref **defs; /* [0..num_defs-1] */
|
||||
struct ref **uses; /* [0..num_uses-1] */
|
||||
|
||||
/* The web to which this web is aliased (coalesced). If NULL, this
|
||||
web is not coalesced into some other (but might still be a target
|
||||
for other webs). */
|
||||
struct web *alias;
|
||||
|
||||
/* With iterated coalescing this is a list of active moves this web
|
||||
is involved in. */
|
||||
struct move_list *moves;
|
||||
|
||||
/* The list implementation. */
|
||||
struct dlist *dlink;
|
||||
|
||||
/* While building webs, out of web-parts, this holds a (partial)
|
||||
list of all refs for this web seen so far. */
|
||||
struct df_link *temp_refs;
|
||||
};
|
||||
|
||||
/* For implementing a single linked list. */
|
||||
struct web_link
|
||||
{
|
||||
struct web_link *next;
|
||||
struct web *web;
|
||||
};
|
||||
|
||||
/* A subconflict is part of a conflict edge to track precisely,
|
||||
which parts of two webs conflict, in case not all of both webs do. */
|
||||
struct sub_conflict
|
||||
{
|
||||
/* The next partial conflict. For one such list the parent-web of
|
||||
all the S webs, resp. the parent of all the T webs are constant. */
|
||||
struct sub_conflict *next;
|
||||
struct web *s;
|
||||
struct web *t;
|
||||
};
|
||||
|
||||
/* This represents an edge in the conflict graph. */
|
||||
struct conflict_link
|
||||
{
|
||||
struct conflict_link *next;
|
||||
|
||||
/* The web we conflict with (the Target of the edge). */
|
||||
struct web *t;
|
||||
|
||||
/* If not the complete source web and T conflict, this points to
|
||||
the list of parts which really conflict. */
|
||||
struct sub_conflict *sub;
|
||||
};
|
||||
|
||||
/* For iterated coalescing the moves can be in these states. */
|
||||
enum move_type
|
||||
{
|
||||
WORKLIST, MV_COALESCED, CONSTRAINED, FROZEN, ACTIVE,
|
||||
LAST_MOVE_TYPE
|
||||
};
|
||||
|
||||
/* Structure of a move we are considering coalescing. */
|
||||
struct move
|
||||
{
|
||||
rtx insn;
|
||||
struct web *source_web;
|
||||
struct web *target_web;
|
||||
enum move_type type;
|
||||
struct dlist *dlink;
|
||||
};
|
||||
|
||||
/* List of moves. */
|
||||
struct move_list
|
||||
{
|
||||
struct move_list *next;
|
||||
struct move *move;
|
||||
};
|
||||
|
||||
/* To have fast access to the defs and uses per insn, we have one such
|
||||
structure per insn. The difference to the normal df.c structures is,
|
||||
that it doesn't contain any NULL refs, which df.c produces in case
|
||||
an insn was modified and it only contains refs to pseudo regs, or to
|
||||
hardregs which matter for allocation, i.e. those not in
|
||||
never_use_colors. */
|
||||
struct ra_insn_info
|
||||
{
|
||||
unsigned int num_defs, num_uses;
|
||||
struct ref **defs, **uses;
|
||||
};
|
||||
|
||||
/* The above structures are stored in this array, indexed by UID... */
|
||||
extern struct ra_insn_info *insn_df;
|
||||
/* ... and the size of that array, as we add insn after setting it up. */
|
||||
extern int insn_df_max_uid;
|
||||
|
||||
/* The interference graph. */
|
||||
extern sbitmap igraph;
|
||||
/* And how to access it. I and J are web indices. If the bit
|
||||
igraph_index(I, J) is set, then they conflict. Note, that
|
||||
if only parts of webs conflict, then also only those parts
|
||||
are noted in the I-graph (i.e. the parent webs not). */
|
||||
#define igraph_index(i, j) ((i) < (j) ? ((j)*((j)-1)/2)+(i) : ((i)*((i)-1)/2)+(j))
|
||||
/* This is the bitmap of all (even partly) conflicting super webs.
|
||||
If bit I*num_webs+J or J*num_webs+I is set, then I and J (both being
|
||||
super web indices) conflict, maybe only partially. Note the
|
||||
asymmetry. */
|
||||
extern sbitmap sup_igraph;
|
||||
|
||||
/* After the first pass, and when interference region spilling is
|
||||
activated, bit I is set, when the insn with UID I contains some
|
||||
refs to pseudos which die at the insn. */
|
||||
extern sbitmap insns_with_deaths;
|
||||
/* The size of that sbitmap. */
|
||||
extern int death_insns_max_uid;
|
||||
|
||||
/* All the web-parts. There are exactly as many web-parts as there
|
||||
are register refs in the insn stream. */
|
||||
extern struct web_part *web_parts;
|
||||
|
||||
/* The number of all webs, including subwebs. */
|
||||
extern unsigned int num_webs;
|
||||
/* The number of just the subwebs. */
|
||||
extern unsigned int num_subwebs;
|
||||
/* The number of all webs, including subwebs. */
|
||||
extern unsigned int num_allwebs;
|
||||
|
||||
/* For easy access when given a web ID: id2web[W->id] == W. */
|
||||
extern struct web **id2web;
|
||||
/* For each hardreg, the web which represents it. */
|
||||
extern struct web *hardreg2web[FIRST_PSEUDO_REGISTER];
|
||||
|
||||
/* Given the ID of a df_ref, which represent a DEF, def2web[ID] is
|
||||
the web, to which this def belongs. */
|
||||
extern struct web **def2web;
|
||||
/* The same as def2web, just for uses. */
|
||||
extern struct web **use2web;
|
||||
|
||||
/* The list of all recognized and coalescable move insns. */
|
||||
extern struct move_list *wl_moves;
|
||||
|
||||
|
||||
/* Some parts of the compiler which we run after colorizing
|
||||
clean reg_renumber[], so we need another place for the colors.
|
||||
This is copied to reg_renumber[] just before returning to toplev. */
|
||||
extern short *ra_reg_renumber;
|
||||
/* The size of that array. Some passes after coloring might have created
|
||||
new pseudos, which will get no color. */
|
||||
extern int ra_max_regno;
|
||||
|
||||
/* The dataflow structure of the current function, while regalloc
|
||||
runs. */
|
||||
extern struct df *df;
|
||||
|
||||
/* For each basic block B we have a bitmap of DF_REF_ID's of uses,
|
||||
which backward reach the end of B. */
|
||||
extern bitmap *live_at_end;
|
||||
|
||||
/* One pass is: collecting registers refs, building I-graph, spilling.
|
||||
And this is how often we already ran that for the current function. */
|
||||
extern int ra_pass;
|
||||
|
||||
/* The maximum pseudo regno, just before register allocation starts.
|
||||
While regalloc runs all pseudos with a larger number represent
|
||||
potentially stack slots or hardregs. I call them stackwebs or
|
||||
stackpseudos. */
|
||||
extern unsigned int max_normal_pseudo;
|
||||
|
||||
/* One of the fixed colors. It must be < FIRST_PSEUDO_REGISTER, because
|
||||
we sometimes want to check the color against a HARD_REG_SET. It must
|
||||
be >= 0, because negative values mean "no color".
|
||||
This color is used for the above stackwebs, when they can't be colored.
|
||||
I.e. normally they would be spilled, but they already represent
|
||||
stackslots. So they are colored with an invalid color. It has
|
||||
the property that even webs which conflict can have that color at the
|
||||
same time. I.e. a stackweb with that color really represents a
|
||||
stackslot. */
|
||||
extern int an_unusable_color;
|
||||
|
||||
/* While building the I-graph, every time insn UID is looked at,
|
||||
number_seen[UID] is incremented. For debugging. */
|
||||
extern int *number_seen;
|
||||
|
||||
/* The different lists on which a web can be (based on the type). */
|
||||
extern struct dlist *web_lists[(int) LAST_NODE_TYPE];
|
||||
#define WEBS(type) (web_lists[(int)(type)])
|
||||
|
||||
/* The largest DF_REF_ID of defs resp. uses, as it was in the
|
||||
last pass. In the first pass this is zero. Used to distinguish new
|
||||
from old references. */
|
||||
extern unsigned int last_def_id;
|
||||
extern unsigned int last_use_id;
|
||||
|
||||
/* Similar for UIDs and number of webs. */
|
||||
extern int last_max_uid;
|
||||
extern unsigned int last_num_webs;
|
||||
|
||||
/* If I is the ID of an old use, and last_check_uses[I] is set,
|
||||
then we must reevaluate it's flow while building the new I-graph. */
|
||||
extern sbitmap last_check_uses;
|
||||
|
||||
/* If nonzero, record_conflict() saves the current conflict list of
|
||||
webs in orig_conflict_list, when not already done so, and the conflict
|
||||
list is going to be changed. It is set, after initially building the
|
||||
I-graph. I.e. new conflicts due to coalescing trigger that copying. */
|
||||
extern unsigned int remember_conflicts;
|
||||
|
||||
/* The maximum UID right before calling regalloc().
|
||||
Used to detect any instructions inserted by the allocator. */
|
||||
extern int orig_max_uid;
|
||||
|
||||
/* A HARD_REG_SET of those color, which can't be used for coalescing.
|
||||
Includes e.g. fixed_regs. */
|
||||
extern HARD_REG_SET never_use_colors;
|
||||
/* For each class C this is reg_class_contents[C] \ never_use_colors. */
|
||||
extern HARD_REG_SET usable_regs[N_REG_CLASSES];
|
||||
/* For each class C the count of hardregs in usable_regs[C]. */
|
||||
extern unsigned int num_free_regs[N_REG_CLASSES];
|
||||
/* For each class C which has num_free_regs[C]==1, the color of the
|
||||
single register in that class, -1 otherwise. */
|
||||
extern int single_reg_in_regclass[N_REG_CLASSES];
|
||||
/* For each mode M the hardregs, which are MODE_OK for M, and have
|
||||
enough space behind them to hold an M value. Additionally
|
||||
if reg R is OK for mode M, but it needs two hardregs, then R+1 will
|
||||
also be set here, even if R+1 itself is not OK for M. I.e. this
|
||||
represent the possible resources which could be taken away be a value
|
||||
in mode M. */
|
||||
extern HARD_REG_SET hardregs_for_mode[NUM_MACHINE_MODES];
|
||||
/* The set of hardregs, for which _any_ mode change is invalid. */
|
||||
extern HARD_REG_SET invalid_mode_change_regs;
|
||||
/* For 0 <= I <= 255, the number of bits set in I. Used to calculate
|
||||
the number of set bits in a HARD_REG_SET. */
|
||||
extern unsigned char byte2bitcount[256];
|
||||
|
||||
/* Expressive helper macros. */
|
||||
#define ID2WEB(I) id2web[I]
|
||||
#define NUM_REGS(W) (((W)->type == PRECOLORED) ? 1 : (W)->num_freedom)
|
||||
#define SUBWEB_P(W) (GET_CODE ((W)->orig_x) == SUBREG)
|
||||
|
||||
/* Constant usable as debug area to ra_debug_msg. */
|
||||
#define DUMP_COSTS 0x0001
|
||||
#define DUMP_WEBS 0x0002
|
||||
#define DUMP_IGRAPH 0x0004
|
||||
#define DUMP_PROCESS 0x0008
|
||||
#define DUMP_COLORIZE 0x0010
|
||||
#define DUMP_ASM 0x0020
|
||||
#define DUMP_CONSTRAINTS 0x0040
|
||||
#define DUMP_RESULTS 0x0080
|
||||
#define DUMP_DF 0x0100
|
||||
#define DUMP_RTL 0x0200
|
||||
#define DUMP_FINAL_RTL 0x0400
|
||||
#define DUMP_REGCLASS 0x0800
|
||||
#define DUMP_SM 0x1000
|
||||
#define DUMP_LAST_FLOW 0x2000
|
||||
#define DUMP_LAST_RTL 0x4000
|
||||
#define DUMP_REBUILD 0x8000
|
||||
#define DUMP_IGRAPH_M 0x10000
|
||||
#define DUMP_VALIDIFY 0x20000
|
||||
#define DUMP_EVER ((unsigned int)-1)
|
||||
#define DUMP_NEARLY_EVER (DUMP_EVER - DUMP_COSTS - DUMP_IGRAPH_M)
|
||||
|
||||
/* All the wanted debug levels as ORing of the various DUMP_xxx
|
||||
constants. */
|
||||
extern unsigned int debug_new_regalloc;
|
||||
|
||||
/* Nonzero means we want biased coloring. */
|
||||
extern int flag_ra_biased;
|
||||
|
||||
/* Nonzero if we want to use improved (and slow) spilling. This
|
||||
includes also interference region spilling (see below). */
|
||||
extern int flag_ra_improved_spilling;
|
||||
|
||||
/* Nonzero for using interference region spilling. Zero for improved
|
||||
Chaintin style spilling (only at deaths). */
|
||||
extern int flag_ra_ir_spilling;
|
||||
|
||||
/* Nonzero if we use optimistic coalescing, zero for iterated
|
||||
coalescing. */
|
||||
extern int flag_ra_optimistic_coalescing;
|
||||
|
||||
/* Nonzero if we want to break aliases of spilled webs. Forced to
|
||||
nonzero, when flag_ra_optimistic_coalescing is. */
|
||||
extern int flag_ra_break_aliases;
|
||||
|
||||
/* Nonzero if we want to merge the spill costs of webs which
|
||||
are coalesced. */
|
||||
extern int flag_ra_merge_spill_costs;
|
||||
|
||||
/* Nonzero if we want to spill at every use, instead of at deaths,
|
||||
or interference region borders. */
|
||||
extern int flag_ra_spill_every_use;
|
||||
|
||||
/* Nonzero to output all notes in the debug dumps. */
|
||||
extern int flag_ra_dump_notes;
|
||||
|
||||
extern void * ra_alloc (size_t);
|
||||
extern void * ra_calloc (size_t);
|
||||
extern int hard_regs_count (HARD_REG_SET);
|
||||
extern rtx ra_emit_move_insn (rtx, rtx);
|
||||
extern void ra_debug_msg (unsigned int, const char *, ...) ATTRIBUTE_PRINTF_2;
|
||||
extern int hard_regs_intersect_p (HARD_REG_SET *, HARD_REG_SET *);
|
||||
extern unsigned int rtx_to_bits (rtx);
|
||||
extern struct web * find_subweb (struct web *, rtx);
|
||||
extern struct web * find_subweb_2 (struct web *, unsigned int);
|
||||
extern struct web * find_web_for_subweb_1 (struct web *);
|
||||
|
||||
#define find_web_for_subweb(w) (((w)->parent_web) \
|
||||
? find_web_for_subweb_1 ((w)->parent_web) \
|
||||
: (w))
|
||||
|
||||
extern void ra_build_realloc (struct df *);
|
||||
extern void ra_build_free (void);
|
||||
extern void ra_build_free_all (struct df *);
|
||||
extern void ra_colorize_init (void);
|
||||
extern void ra_colorize_free_all (void);
|
||||
extern void ra_rewrite_init (void);
|
||||
|
||||
extern void ra_print_rtx (FILE *, rtx, int);
|
||||
extern void ra_print_rtx_top (FILE *, rtx, int);
|
||||
extern void ra_debug_rtx (rtx);
|
||||
extern void ra_debug_insns (rtx, int);
|
||||
extern void ra_debug_bbi (int);
|
||||
extern void ra_print_rtl_with_bb (FILE *, rtx);
|
||||
extern void dump_igraph (struct df *);
|
||||
extern void dump_igraph_machine (void);
|
||||
extern void dump_constraints (void);
|
||||
extern void dump_cost (unsigned int);
|
||||
extern void dump_graph_cost (unsigned int, const char *);
|
||||
extern void dump_ra (struct df *);
|
||||
extern void dump_number_seen (void);
|
||||
extern void dump_static_insn_cost (FILE *, const char *, const char *);
|
||||
extern void dump_web_conflicts (struct web *);
|
||||
extern void dump_web_insns (struct web*);
|
||||
extern int web_conflicts_p (struct web *, struct web *);
|
||||
extern void debug_hard_reg_set (HARD_REG_SET);
|
||||
|
||||
extern void remove_list (struct dlist *, struct dlist **);
|
||||
extern struct dlist * pop_list (struct dlist **);
|
||||
extern void record_conflict (struct web *, struct web *);
|
||||
extern int memref_is_stack_slot (rtx);
|
||||
extern void build_i_graph (struct df *);
|
||||
extern void put_web (struct web *, enum ra_node_type);
|
||||
extern void remove_web_from_list (struct web *);
|
||||
extern void reset_lists (void);
|
||||
extern struct web * alias (struct web *);
|
||||
extern void merge_moves (struct web *, struct web *);
|
||||
extern void ra_colorize_graph (struct df *);
|
||||
|
||||
extern void actual_spill (void);
|
||||
extern void emit_colors (struct df *);
|
||||
extern void delete_moves (void);
|
||||
extern void setup_renumber (int);
|
||||
extern void remove_suspicious_death_notes (void);
|
||||
|
||||
#endif /* GCC_RA_H */
|
@ -1,5 +1,5 @@
|
||||
/* toplev.h - Various declarations for functions found in toplev.c
|
||||
Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004
|
||||
Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
@ -134,7 +134,6 @@ extern int flag_unroll_all_loops;
|
||||
extern int flag_unswitch_loops;
|
||||
extern int flag_cprop_registers;
|
||||
extern int time_report;
|
||||
extern int flag_new_regalloc;
|
||||
extern int flag_tree_based_profiling;
|
||||
|
||||
/* Things to do with target switches. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user