mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-24 19:21:12 +08:00
[multiple changes]
2002-07-15 Michael Matz <matz@suse.de>, Daniel Berlin <dberlin@dberlin.org>, Denis Chertykov <denisc@overta.ru> Add a new register allocator. * ra.c: New file. * ra.h: New file. * ra-build.c: New file. * ra-colorize.c: New file. * ra-debug.c: New file. * ra-rewrite.c: New file. * Makefile.in (ra.o, ra-build.o, ra-colorize.o, ra-debug.o, (ra-rewrite.o): New .o files for libbackend.a. (GTFILES): Add basic-block.h. * toplev.c (flag_new_regalloc): New. (f_options): New option "new-ra". (rest_of_compilation): Call initialize_uninitialized_subregs() only for the old allocator. If flag_new_regalloc is set, call new allocator, instead of local_alloc(), global_alloc() and friends. * doc/invoke.texi: Document -fnew-ra. * basic-block.h (FOR_ALL_BB): New. * config/rs6000/rs6000.c (print_operand): Write small constants as @l+80. * df.c (read_modify_subreg_p): Narrow down cases for a rmw subreg. (df_reg_table_realloc): Make size at least as large as max_reg_num(). (df_insn_table_realloc): Size argument now is absolute, not relative. Changed all callers. * gengtype.c (main): Add the pseudo-type "HARD_REG_SET". * regclass.c (reg_scan_mark_refs): Ignore NULL rtx's. 2002-06-20 Michael Matz <matz@suse.de> * df.h (struct ref.id): Make unsigned. * df.c (df_bb_reg_def_chain_create): Remove unsigned cast. 2002-06-13 Michael Matz <matz@suse.de> * df.h (DF_REF_MODE_CHANGE): New flag. * df.c (df_def_record_1, df_uses_record): Set this flag for refs involving subregs with invalid mode changes, when CLASS_CANNOT_CHANGE_MODE is defined. 2002-05-07 Michael Matz <matz@suse.de> * reload1.c (fixup_abnormal_edges): Don't insert on NULL edge. 2002-05-03 Michael Matz <matz@suse.de> * sbitmap.c (sbitmap_difference): Accept sbitmaps of different size. Sat Feb 2 18:58:07 2002 Denis Chertykov <denisc@overta.ru> * regclass.c (regclass): Work with all regs which have sets or refs. (reg_scan_mark_refs): Count regs inside (clobber ...). 2002-01-04 Michael Matz <matzmich@cs.tu-berlin.de> * df.c (df_ref_record): Correctly calculate SUBREGs of hardregs. (df_bb_reg_def_chain_create, df_bb_reg_use_chain_create): Only add new refs. (df_bb_refs_update): Don't clear insns_modified here, ... (df_analyse): ... but here. * sbitmap.c (dump_sbitmap_file): New. (debug_sbitmap): Use it. * sbitmap.h (dump_sbitmap_file): Add prototype. 2001-08-07 Daniel Berlin <dan@cgsoftware.com> * df.c (df_insn_modify): Grow the UID table if necessary, rather than assume all emits go through df_insns_modify. 2001-07-26 Daniel Berlin <dan@cgsoftware.com> * regclass.c (reg_scan_mark_refs): When we increase REG_N_SETS, increase REG_N_REFS (like flow does), so that regclass doesn't think a reg is useless, and thus, not calculate a class, when it really should have. 2001-01-28 Daniel Berlin <dberlin@redhat.com> * sbitmap.h (EXECUTE_IF_SET_IN_SBITMAP_REV): New macro, needed for dataflow analysis. From-SVN: r55458
This commit is contained in:
parent
7bc7d27b87
commit
ed8d29205b
@ -1,3 +1,96 @@
|
||||
2002-07-15 Michael Matz <matz@suse.de>,
|
||||
Daniel Berlin <dberlin@dberlin.org>,
|
||||
Denis Chertykov <denisc@overta.ru>
|
||||
|
||||
Add a new register allocator.
|
||||
|
||||
* ra.c: New file.
|
||||
* ra.h: New file.
|
||||
* ra-build.c: New file.
|
||||
* ra-colorize.c: New file.
|
||||
* ra-debug.c: New file.
|
||||
* ra-rewrite.c: New file.
|
||||
|
||||
* Makefile.in (ra.o, ra-build.o, ra-colorize.o, ra-debug.o,
|
||||
(ra-rewrite.o): New .o files for libbackend.a.
|
||||
(GTFILES): Add basic-block.h.
|
||||
|
||||
* toplev.c (flag_new_regalloc): New.
|
||||
(f_options): New option "new-ra".
|
||||
(rest_of_compilation): Call initialize_uninitialized_subregs()
|
||||
only for the old allocator. If flag_new_regalloc is set, call
|
||||
new allocator, instead of local_alloc(), global_alloc() and
|
||||
friends.
|
||||
|
||||
* doc/invoke.texi: Document -fnew-ra.
|
||||
* basic-block.h (FOR_ALL_BB): New.
|
||||
* config/rs6000/rs6000.c (print_operand): Write small constants
|
||||
as @l+80.
|
||||
|
||||
* df.c (read_modify_subreg_p): Narrow down cases for a rmw subreg.
|
||||
(df_reg_table_realloc): Make size at least as large as max_reg_num().
|
||||
(df_insn_table_realloc): Size argument now is absolute, not relative.
|
||||
Changed all callers.
|
||||
|
||||
* gengtype.c (main): Add the pseudo-type "HARD_REG_SET".
|
||||
* regclass.c (reg_scan_mark_refs): Ignore NULL rtx's.
|
||||
|
||||
2002-06-20 Michael Matz <matz@suse.de>
|
||||
|
||||
* df.h (struct ref.id): Make unsigned.
|
||||
* df.c (df_bb_reg_def_chain_create): Remove unsigned cast.
|
||||
|
||||
2002-06-13 Michael Matz <matz@suse.de>
|
||||
|
||||
* df.h (DF_REF_MODE_CHANGE): New flag.
|
||||
* df.c (df_def_record_1, df_uses_record): Set this flag for refs
|
||||
involving subregs with invalid mode changes, when
|
||||
CLASS_CANNOT_CHANGE_MODE is defined.
|
||||
|
||||
2002-05-07 Michael Matz <matz@suse.de>
|
||||
|
||||
* reload1.c (fixup_abnormal_edges): Don't insert on NULL edge.
|
||||
|
||||
2002-05-03 Michael Matz <matz@suse.de>
|
||||
|
||||
* sbitmap.c (sbitmap_difference): Accept sbitmaps of different size.
|
||||
|
||||
Sat Feb 2 18:58:07 2002 Denis Chertykov <denisc@overta.ru>
|
||||
|
||||
* regclass.c (regclass): Work with all regs which have sets or
|
||||
refs.
|
||||
(reg_scan_mark_refs): Count regs inside (clobber ...).
|
||||
|
||||
2002-01-04 Michael Matz <matzmich@cs.tu-berlin.de>
|
||||
|
||||
* df.c (df_ref_record): Correctly calculate SUBREGs of hardregs.
|
||||
(df_bb_reg_def_chain_create, df_bb_reg_use_chain_create): Only
|
||||
add new refs.
|
||||
(df_bb_refs_update): Don't clear insns_modified here, ...
|
||||
(df_analyse): ... but here.
|
||||
|
||||
* sbitmap.c (dump_sbitmap_file): New.
|
||||
(debug_sbitmap): Use it.
|
||||
|
||||
* sbitmap.h (dump_sbitmap_file): Add prototype.
|
||||
|
||||
2001-08-07 Daniel Berlin <dan@cgsoftware.com>
|
||||
|
||||
* df.c (df_insn_modify): Grow the UID table if necessary, rather
|
||||
than assume all emits go through df_insns_modify.
|
||||
|
||||
2001-07-26 Daniel Berlin <dan@cgsoftware.com>
|
||||
|
||||
* regclass.c (reg_scan_mark_refs): When we increase REG_N_SETS,
|
||||
increase REG_N_REFS (like flow does), so that regclass doesn't
|
||||
think a reg is useless, and thus, not calculate a class, when it
|
||||
really should have.
|
||||
|
||||
2001-01-28 Daniel Berlin <dberlin@redhat.com>
|
||||
|
||||
* sbitmap.h (EXECUTE_IF_SET_IN_SBITMAP_REV): New macro, needed for
|
||||
dataflow analysis.
|
||||
|
||||
2002-07-15 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR middle-end/7245
|
||||
|
@ -731,7 +731,8 @@ OBJS = alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o \
|
||||
insn-extract.o insn-opinit.o insn-output.o insn-peep.o insn-recog.o \
|
||||
integrate.o intl.o jump.o langhooks.o lcm.o lists.o local-alloc.o \
|
||||
loop.o mbchar.o optabs.o params.o predict.o print-rtl.o print-tree.o \
|
||||
profile.o real.o recog.o reg-stack.o regclass.o regmove.o regrename.o \
|
||||
profile.o ra.o ra-build.o ra-colorize.o ra-debug.o ra-rewrite.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 \
|
||||
sibcall.o simplify-rtx.o ssa.o ssa-ccp.o ssa-dce.o stmt.o \
|
||||
@ -1562,6 +1563,19 @@ global.o : global.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h reload.h function.h
|
||||
$(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h insn-config.h output.h toplev.h \
|
||||
$(TM_P_H)
|
||||
varray.o : varray.c $(CONFIG_H) $(SYSTEM_H) varray.h $(GGC_H) errors.h
|
||||
ra.o : ra.c $(CONFIG_H) $(SYSTEM_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) $(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
|
||||
ra-colorize.o : ra-colorize.c $(CONFIG_H) $(SYSTEM_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) $(RTL_H) insn-config.h \
|
||||
$(RECOG_H) function.h hard-reg-set.h $(BASIC_BLOCK_H) df.h output.h ra.h
|
||||
ra-rewrite.o : ra-rewrite.c $(CONFIG_H) $(SYSTEM_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.o : reload.c $(CONFIG_H) $(SYSTEM_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)
|
||||
@ -1820,7 +1834,8 @@ GTFILES = $(GCONFIG_H) $(srcdir)/location.h \
|
||||
$(srcdir)/except.c $(srcdir)/explow.c $(srcdir)/expr.c \
|
||||
$(srcdir)/fold-const.c $(srcdir)/function.c \
|
||||
$(srcdir)/gcse.c $(srcdir)/integrate.c $(srcdir)/lists.c $(srcdir)/optabs.c \
|
||||
$(srcdir)/profile.c $(srcdir)/regclass.c $(srcdir)/reg-stack.c \
|
||||
$(srcdir)/profile.c $(srcdir)/ra-build.c $(srcdir)/regclass.c \
|
||||
$(srcdir)/reg-stack.c \
|
||||
$(srcdir)/sdbout.c $(srcdir)/stmt.c $(srcdir)/stor-layout.c \
|
||||
$(srcdir)/tree.c $(srcdir)/varasm.c \
|
||||
$(out_file) \
|
||||
@ -1836,7 +1851,7 @@ gt-integrate.h gt-stmt.h gt-tree.h gt-varasm.h gt-emit-rtl.h : s-gtype; @true
|
||||
gt-explow.h gt-stor-layout.h gt-regclass.h gt-lists.h : s-gtype; @true
|
||||
gt-alias.h gt-cselib.h gt-fold-const.h gt-gcse.h gt-profile.h : s-gtype; @true
|
||||
gt-expr.h gt-sdbout.h gt-optabs.h gt-bitmap.h gt-dwarf2out.h : s-gtype ; @true
|
||||
gt-reg-stack.h gt-dependence.h : s-gtype ; @true
|
||||
gt-ra-build.h gt-reg-stack.h gt-dependence.h : s-gtype ; @true
|
||||
gt-c-common.h gt-c-decl.h gt-c-parse.h gt-c-pragma.h : s-gtype; @true
|
||||
gt-c-objc-common.h gtype-c.h gt-location.h : s-gtype ; @true
|
||||
|
||||
|
@ -261,6 +261,12 @@ extern varray_type basic_block_info;
|
||||
#define FOR_EACH_BB_REVERSE(BB) \
|
||||
FOR_BB_BETWEEN (BB, EXIT_BLOCK_PTR->prev_bb, ENTRY_BLOCK_PTR, prev_bb)
|
||||
|
||||
/* Cycles through _all_ basic blocks, even the fake ones (entry and
|
||||
exit block). */
|
||||
|
||||
#define FOR_ALL_BB(BB) \
|
||||
for (BB = ENTRY_BLOCK_PTR; BB; BB = BB->next_bb)
|
||||
|
||||
/* What registers are live at the setjmp call. */
|
||||
|
||||
extern regset regs_live_at_setjmp;
|
||||
|
@ -6258,6 +6258,11 @@ print_operand (file, x, code)
|
||||
output_operand_lossage ("invalid %%K value");
|
||||
print_operand_address (file, XEXP (XEXP (x, 0), 0));
|
||||
fputs ("@l", file);
|
||||
/* For GNU as, there must be a non-alphanumeric character
|
||||
between 'l' and the number. The '-' is added by
|
||||
print_operand() already. */
|
||||
if (INTVAL (XEXP (XEXP (x, 0), 1)) >= 0)
|
||||
fputs ("+", file);
|
||||
print_operand (file, XEXP (XEXP (x, 0), 1), 0);
|
||||
}
|
||||
return;
|
||||
|
13
gcc/df.h
13
gcc/df.h
@ -50,7 +50,16 @@ struct df_link
|
||||
|
||||
enum df_ref_flags
|
||||
{
|
||||
DF_REF_READ_WRITE = 1
|
||||
DF_REF_READ_WRITE = 1,
|
||||
|
||||
/* This flag is set on register references itself representing a or
|
||||
being inside a subreg on machines which have CLASS_CANNOT_CHANGE_MODE
|
||||
and where the mode change of that subreg expression is invalid for
|
||||
this class. Note, that this flag can also be set on df_refs
|
||||
representing the REG itself (i.e. one might not see the subreg
|
||||
anyore). Also note, that this flag is set also for hardreg refs.
|
||||
I.e. you must check yourself if it's a pseudo. */
|
||||
DF_REF_MODE_CHANGE = 2
|
||||
};
|
||||
|
||||
/* Define a register reference structure. */
|
||||
@ -61,7 +70,7 @@ struct ref
|
||||
rtx *loc; /* Loc is the location of the reg. */
|
||||
struct df_link *chain; /* Head of def-use or use-def chain. */
|
||||
enum df_ref_type type; /* Type of ref. */
|
||||
int id; /* Ref index. */
|
||||
unsigned int id; /* Ref index. */
|
||||
enum df_ref_flags flags; /* Various flags. */
|
||||
};
|
||||
|
||||
|
@ -270,7 +270,7 @@ in the following sections.
|
||||
-fif-conversion -fif-conversion2 @gol
|
||||
-finline-functions -finline-limit=@var{n} -fkeep-inline-functions @gol
|
||||
-fkeep-static-consts -fmerge-constants -fmerge-all-constants @gol
|
||||
-fmove-all-movables -fno-default-inline -fno-defer-pop @gol
|
||||
-fmove-all-movables -fnew-ra -fno-default-inline -fno-defer-pop @gol
|
||||
-fno-function-cse -fno-guess-branch-probability @gol
|
||||
-fno-inline -fno-math-errno -fno-peephole -fno-peephole2 @gol
|
||||
-funsafe-math-optimizations -fno-trapping-math @gol
|
||||
@ -3395,6 +3395,12 @@ types. Languages like C or C++ require each non-automatic variable to
|
||||
have distinct location, so using this option will result in non-conforming
|
||||
behavior.
|
||||
|
||||
@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 -fno-function-cse
|
||||
@opindex fno-function-cse
|
||||
Do not put function addresses in registers; make each instruction that
|
||||
|
@ -1939,6 +1939,10 @@ main(argc, argv)
|
||||
strlen ("void"))),
|
||||
&pos);
|
||||
|
||||
do_typedef ("HARD_REG_SET", create_array (
|
||||
create_scalar_type ("unsigned long", strlen ("unsigned long")),
|
||||
"2"), &pos);
|
||||
|
||||
for (i = 0; i < NUM_GT_FILES; i++)
|
||||
{
|
||||
int dupflag = 0;
|
||||
|
3264
gcc/ra-build.c
Normal file
3264
gcc/ra-build.c
Normal file
File diff suppressed because it is too large
Load Diff
2734
gcc/ra-colorize.c
Normal file
2734
gcc/ra-colorize.c
Normal file
File diff suppressed because it is too large
Load Diff
1118
gcc/ra-debug.c
Normal file
1118
gcc/ra-debug.c
Normal file
File diff suppressed because it is too large
Load Diff
1985
gcc/ra-rewrite.c
Normal file
1985
gcc/ra-rewrite.c
Normal file
File diff suppressed because it is too large
Load Diff
902
gcc/ra.c
Normal file
902
gcc/ra.c
Normal file
@ -0,0 +1,902 @@
|
||||
/* Graph coloring register allocator
|
||||
Copyright (C) 2001, 2002 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 "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"
|
||||
|
||||
#define obstack_chunk_alloc xmalloc
|
||||
#define obstack_chunk_free free
|
||||
|
||||
/* 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 possile
|
||||
* 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 struct obstack ra_obstack;
|
||||
static void create_insn_info PARAMS ((struct df *));
|
||||
static void free_insn_info PARAMS ((void));
|
||||
static void alloc_mem PARAMS ((struct df *));
|
||||
static void free_mem PARAMS ((struct df *));
|
||||
static void free_all_mem PARAMS ((struct df *df));
|
||||
static int one_pass PARAMS ((struct df *, int));
|
||||
static void check_df PARAMS ((struct df *));
|
||||
static void init_ra PARAMS ((void));
|
||||
|
||||
void reg_alloc PARAMS ((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];
|
||||
HARD_REG_SET hardregs_for_mode[NUM_MACHINE_MODES];
|
||||
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)
|
||||
size_t size;
|
||||
{
|
||||
return obstack_alloc (&ra_obstack, size);
|
||||
}
|
||||
|
||||
/* Like ra_alloc(), but clear the returned memory. */
|
||||
|
||||
void *
|
||||
ra_calloc (size)
|
||||
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 (rs)
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 (x, y)
|
||||
rtx x, 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 (df)
|
||||
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;
|
||||
}
|
||||
if (refs_for_insn_df + (df->def_id + df->use_id) < act_refs)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* Free the insn_df structures. */
|
||||
|
||||
static void
|
||||
free_insn_info ()
|
||||
{
|
||||
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 (web, reg)
|
||||
struct web *web;
|
||||
rtx reg;
|
||||
{
|
||||
struct web *w;
|
||||
if (GET_CODE (reg) != SUBREG)
|
||||
abort ();
|
||||
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 (web, size_word)
|
||||
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 (subweb)
|
||||
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 (a, b)
|
||||
HARD_REG_SET *a, *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 (df)
|
||||
struct df *df;
|
||||
{
|
||||
int i;
|
||||
ra_build_realloc (df);
|
||||
if (!live_at_end)
|
||||
{
|
||||
live_at_end = (bitmap *) 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 (df)
|
||||
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 (df)
|
||||
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 (df, rebuild)
|
||||
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 ()
|
||||
{
|
||||
int i;
|
||||
HARD_REG_SET rs;
|
||||
#ifdef ELIMINABLE_REGS
|
||||
static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
|
||||
unsigned int j;
|
||||
#endif
|
||||
int need_fp
|
||||
= (! flag_omit_frame_pointer
|
||||
#ifdef EXIT_IGNORE_STACK
|
||||
|| (current_function_calls_alloca && EXIT_IGNORE_STACK)
|
||||
#endif
|
||||
|| 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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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;
|
||||
if (an_unusable_color == FIRST_PSEUDO_REGISTER)
|
||||
abort ();
|
||||
|
||||
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 aborts if it violates some
|
||||
invariances we expect. */
|
||||
|
||||
static void
|
||||
check_df (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)
|
||||
if (!link->ref || bitmap_bit_p (empty_defs, DF_REF_ID (link->ref))
|
||||
|| bitmap_bit_p (b, DF_REF_ID (link->ref)))
|
||||
abort ();
|
||||
else
|
||||
bitmap_set_bit (b, DF_REF_ID (link->ref));
|
||||
|
||||
bitmap_clear (b);
|
||||
for (link = DF_INSN_USES (df, insn); link; link = link->next)
|
||||
if (!link->ref || bitmap_bit_p (empty_uses, DF_REF_ID (link->ref))
|
||||
|| bitmap_bit_p (b, DF_REF_ID (link->ref)))
|
||||
abort ();
|
||||
else
|
||||
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)
|
||||
if (!link->ref || bitmap_bit_p (empty_defs, DF_REF_ID (link->ref))
|
||||
|| bitmap_bit_p (b, DF_REF_ID (link->ref)))
|
||||
abort ();
|
||||
else
|
||||
bitmap_set_bit (b, DF_REF_ID (link->ref));
|
||||
|
||||
bitmap_clear (b);
|
||||
for (link = df->regs[regno].uses; link; link = link->next)
|
||||
if (!link->ref || bitmap_bit_p (empty_uses, DF_REF_ID (link->ref))
|
||||
|| bitmap_bit_p (b, DF_REF_ID (link->ref)))
|
||||
abort ();
|
||||
else
|
||||
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 ()
|
||||
{
|
||||
int changed;
|
||||
FILE *ra_dump_file = rtl_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 existance of the return value USE as
|
||||
one of the last insns. Add it if it's not there anymore. */
|
||||
if (last)
|
||||
{
|
||||
edge e;
|
||||
for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
|
||||
{
|
||||
basic_block bb = e->src;
|
||||
last = bb->end;
|
||||
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 usefull 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 (!rtl_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
|
||||
explicitely requested. */
|
||||
if ((debug_new_regalloc & DUMP_REGCLASS) == 0)
|
||||
rtl_dump_file = NULL;
|
||||
regclass (get_insns (), max_reg_num (), rtl_dump_file);
|
||||
rtl_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_analyse (df, (ra_pass == 1) ? 0 : (bitmap) -1,
|
||||
DF_HARD_REGS | DF_RD_CHAIN | DF_RU_CHAIN);
|
||||
|
||||
if ((debug_new_regalloc & DUMP_DF) != 0)
|
||||
{
|
||||
rtx insn;
|
||||
df_dump (df, DF_HARD_REGS, rtl_dump_file);
|
||||
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||
if (INSN_P (insn))
|
||||
df_insn_debug_regno (df, insn, rtl_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)
|
||||
rtl_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 usefull classes too. */
|
||||
regclass (get_insns (), max_reg_num (), rtl_dump_file);
|
||||
rtl_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 (rtl_dump_file, get_insns ());
|
||||
fflush (rtl_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 (rtl_dump_file, get_insns ());
|
||||
|
||||
/* We might have new pseudos, so allocate the info arrays for them. */
|
||||
if ((debug_new_regalloc & DUMP_SM) == 0)
|
||||
rtl_dump_file = NULL;
|
||||
no_new_pseudos = 0;
|
||||
allocate_reg_info (max_reg_num (), FALSE, FALSE);
|
||||
no_new_pseudos = 1;
|
||||
rtl_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)
|
||||
rtl_dump_file = NULL;
|
||||
life_analysis (get_insns (), rtl_dump_file,
|
||||
PROP_DEATH_NOTES | PROP_LOG_LINKS | PROP_REG_INFO);
|
||||
cleanup_cfg (CLEANUP_EXPENSIVE);
|
||||
recompute_reg_usage (get_insns (), TRUE);
|
||||
if (rtl_dump_file)
|
||||
dump_flow_info (rtl_dump_file);
|
||||
rtl_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 (rtl_dump_file, get_insns ());
|
||||
dump_static_insn_cost (rtl_dump_file,
|
||||
"after allocation/spilling, before reload", NULL);
|
||||
|
||||
/* Allocate the reg_equiv_memory_loc array for reload. */
|
||||
reg_equiv_memory_loc = (rtx *) xcalloc (max_regno, sizeof (rtx));
|
||||
/* 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 (), rtl_dump_file);
|
||||
}
|
||||
|
||||
/*
|
||||
vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4:
|
||||
*/
|
624
gcc/ra.h
Normal file
624
gcc/ra.h
Normal file
@ -0,0 +1,624 @@
|
||||
/* Graph coloring register allocator
|
||||
Copyright (C) 2001, 2002 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. */
|
||||
|
||||
/* 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 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 implicitely 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, 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(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 successfull 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 an 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
|
||||
assymetry. */
|
||||
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, buiding 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 refrences. */
|
||||
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 mode M the hardregs, which are MODE_OK for M, and have
|
||||
enough space behind them to hold an M value. Additinally
|
||||
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];
|
||||
/* 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 intereference 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 inline void * ra_alloc PARAMS ((size_t));
|
||||
extern inline void * ra_calloc PARAMS ((size_t));
|
||||
extern int hard_regs_count PARAMS ((HARD_REG_SET));
|
||||
extern rtx ra_emit_move_insn PARAMS ((rtx, rtx));
|
||||
extern void ra_debug_msg PARAMS ((unsigned int,
|
||||
const char *, ...)) ATTRIBUTE_PRINTF_2;
|
||||
extern int hard_regs_intersect_p PARAMS ((HARD_REG_SET *, HARD_REG_SET *));
|
||||
extern unsigned int rtx_to_bits PARAMS ((rtx));
|
||||
extern struct web * find_subweb PARAMS ((struct web *, rtx));
|
||||
extern struct web * find_subweb_2 PARAMS ((struct web *, unsigned int));
|
||||
extern struct web * find_web_for_subweb_1 PARAMS ((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 PARAMS ((struct df *));
|
||||
extern void ra_build_free PARAMS ((void));
|
||||
extern void ra_build_free_all PARAMS ((struct df *));
|
||||
extern void ra_colorize_init PARAMS ((void));
|
||||
extern void ra_colorize_free_all PARAMS ((void));
|
||||
extern void ra_rewrite_init PARAMS ((void));
|
||||
|
||||
extern void ra_print_rtx PARAMS ((FILE *, rtx, int));
|
||||
extern void ra_print_rtx_top PARAMS ((FILE *, rtx, int));
|
||||
extern void ra_debug_rtx PARAMS ((rtx));
|
||||
extern void ra_debug_insns PARAMS ((rtx, int));
|
||||
extern void ra_debug_bbi PARAMS ((int));
|
||||
extern void ra_print_rtl_with_bb PARAMS ((FILE *, rtx));
|
||||
extern void dump_igraph PARAMS ((struct df *));
|
||||
extern void dump_igraph_machine PARAMS ((void));
|
||||
extern void dump_constraints PARAMS ((void));
|
||||
extern void dump_cost PARAMS ((unsigned int));
|
||||
extern void dump_graph_cost PARAMS ((unsigned int, const char *));
|
||||
extern void dump_ra PARAMS ((struct df *));
|
||||
extern void dump_number_seen PARAMS ((void));
|
||||
extern void dump_static_insn_cost PARAMS ((FILE *, const char *,
|
||||
const char *));
|
||||
extern void dump_web_conflicts PARAMS ((struct web *));
|
||||
extern void dump_web_insns PARAMS ((struct web*));
|
||||
extern int web_conflicts_p PARAMS ((struct web *, struct web *));
|
||||
extern void debug_hard_reg_set PARAMS ((HARD_REG_SET));
|
||||
|
||||
extern void remove_list PARAMS ((struct dlist *, struct dlist **));
|
||||
extern struct dlist * pop_list PARAMS ((struct dlist **));
|
||||
extern void record_conflict PARAMS ((struct web *, struct web *));
|
||||
extern int memref_is_stack_slot PARAMS ((rtx));
|
||||
extern void build_i_graph PARAMS ((struct df *));
|
||||
extern void put_web PARAMS ((struct web *, enum node_type));
|
||||
extern void remove_web_from_list PARAMS ((struct web *));
|
||||
extern void reset_lists PARAMS ((void));
|
||||
extern struct web * alias PARAMS ((struct web *));
|
||||
extern void merge_moves PARAMS ((struct web *, struct web *));
|
||||
extern void ra_colorize_graph PARAMS ((struct df *));
|
||||
|
||||
extern void actual_spill PARAMS ((void));
|
||||
extern void emit_colors PARAMS ((struct df *));
|
||||
extern void delete_moves PARAMS ((void));
|
||||
extern void setup_renumber PARAMS ((int));
|
||||
extern void remove_suspicious_death_notes PARAMS ((void));
|
@ -1317,7 +1317,7 @@ regclass (f, nregs, dump)
|
||||
|
||||
/* In non-optimizing compilation REG_N_REFS is not initialized
|
||||
yet. */
|
||||
if (optimize && !REG_N_REFS (i))
|
||||
if (optimize && !REG_N_REFS (i) && !REG_N_SETS (i))
|
||||
continue;
|
||||
|
||||
for (class = (int) ALL_REGS - 1; class > 0; class--)
|
||||
@ -2397,6 +2397,8 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno)
|
||||
rtx dest;
|
||||
rtx note;
|
||||
|
||||
if (!x)
|
||||
return;
|
||||
code = GET_CODE (x);
|
||||
switch (code)
|
||||
{
|
||||
@ -2423,6 +2425,10 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno)
|
||||
REGNO_LAST_UID (regno) = INSN_UID (insn);
|
||||
if (REGNO_FIRST_UID (regno) == 0)
|
||||
REGNO_FIRST_UID (regno) = INSN_UID (insn);
|
||||
/* If we are called by reg_scan_update() (indicated by min_regno
|
||||
being set), we also need to update the reference count. */
|
||||
if (min_regno)
|
||||
REG_N_REFS (regno)++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -2439,6 +2445,18 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno)
|
||||
reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno);
|
||||
break;
|
||||
|
||||
case CLOBBER:
|
||||
{
|
||||
rtx reg = XEXP (x, 0);
|
||||
if (REG_P (reg)
|
||||
&& REGNO (reg) >= min_regno)
|
||||
{
|
||||
REG_N_SETS (REGNO (reg))++;
|
||||
REG_N_REFS (REGNO (reg))++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SET:
|
||||
/* Count a set of the destination if it is a register. */
|
||||
for (dest = SET_DEST (x);
|
||||
|
@ -9475,12 +9475,21 @@ fixup_abnormal_edges ()
|
||||
{
|
||||
delete_insn (insn);
|
||||
|
||||
/* We're not deleting it, we're moving it. */
|
||||
INSN_DELETED_P (insn) = 0;
|
||||
PREV_INSN (insn) = NULL_RTX;
|
||||
NEXT_INSN (insn) = NULL_RTX;
|
||||
/* Sometimes there's still the return value USE.
|
||||
If it's placed after a trapping call (i.e. that
|
||||
call is the last insn anyway), we have no fallthru
|
||||
edge. Simply delete this use and don't try to insert
|
||||
on the non-existant edge. */
|
||||
if (GET_CODE (PATTERN (insn)) != USE)
|
||||
{
|
||||
rtx seq;
|
||||
/* We're not deleting it, we're moving it. */
|
||||
INSN_DELETED_P (insn) = 0;
|
||||
PREV_INSN (insn) = NULL_RTX;
|
||||
NEXT_INSN (insn) = NULL_RTX;
|
||||
|
||||
insert_insn_on_edge (insn, e);
|
||||
insert_insn_on_edge (insn, e);
|
||||
}
|
||||
}
|
||||
insn = next;
|
||||
}
|
||||
|
@ -218,13 +218,26 @@ void
|
||||
sbitmap_difference (dst, a, b)
|
||||
sbitmap dst, a, b;
|
||||
{
|
||||
unsigned int i, n = dst->size;
|
||||
unsigned int i, dst_size = dst->size;
|
||||
unsigned int min_size = dst->size;
|
||||
sbitmap_ptr dstp = dst->elms;
|
||||
sbitmap_ptr ap = a->elms;
|
||||
sbitmap_ptr bp = b->elms;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
*dstp++ = *ap++ & ~*bp++;
|
||||
|
||||
/* A should be at least as large as DEST, to have a defined source. */
|
||||
if (a->size < dst_size)
|
||||
abort ();
|
||||
/* If minuend is smaller, we simply pretend it to be zero bits, i.e.
|
||||
only copy the subtrahend into dest. */
|
||||
if (b->size < min_size)
|
||||
min_size = b->size;
|
||||
for (i = 0; i < min_size; i++)
|
||||
*dstp++ = *ap++ & (~*bp++);
|
||||
/* Now fill the rest of dest from A, if B was too short.
|
||||
This makes sense only when destination and A differ. */
|
||||
if (dst != a && i != dst_size)
|
||||
for (; i < dst_size; i++)
|
||||
*dstp++ = *ap++;
|
||||
}
|
||||
|
||||
/* Set DST to be (A and B).
|
||||
@ -658,27 +671,35 @@ dump_sbitmap (file, bmap)
|
||||
}
|
||||
|
||||
void
|
||||
debug_sbitmap (bmap)
|
||||
dump_sbitmap_file (file, bmap)
|
||||
FILE *file;
|
||||
sbitmap bmap;
|
||||
{
|
||||
unsigned int i, pos;
|
||||
|
||||
fprintf (stderr, "n_bits = %d, set = {", bmap->n_bits);
|
||||
fprintf (file, "n_bits = %d, set = {", bmap->n_bits);
|
||||
|
||||
for (pos = 30, i = 0; i < bmap->n_bits; i++)
|
||||
if (TEST_BIT (bmap, i))
|
||||
{
|
||||
if (pos > 70)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (file, "\n ");
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
fprintf (stderr, "%d ", i);
|
||||
pos += 1 + (i >= 10) + (i >= 100);
|
||||
fprintf (file, "%d ", i);
|
||||
pos += 2 + (i >= 10) + (i >= 100) + (i >= 1000);
|
||||
}
|
||||
|
||||
fprintf (stderr, "}\n");
|
||||
fprintf (file, "}\n");
|
||||
}
|
||||
|
||||
void
|
||||
debug_sbitmap (bmap)
|
||||
sbitmap bmap;
|
||||
{
|
||||
dump_sbitmap_file (stderr, bmap);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -85,12 +85,41 @@ do { \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define EXECUTE_IF_SET_IN_SBITMAP_REV(SBITMAP, N, CODE) \
|
||||
do { \
|
||||
unsigned int word_num_; \
|
||||
unsigned int bit_num_; \
|
||||
unsigned int size_ = (SBITMAP)->size; \
|
||||
SBITMAP_ELT_TYPE *ptr_ = (SBITMAP)->elms; \
|
||||
\
|
||||
for (word_num_ = size_; word_num_ > 0; word_num_--) \
|
||||
{ \
|
||||
SBITMAP_ELT_TYPE word_ = ptr_[word_num_ - 1]; \
|
||||
\
|
||||
if (word_ != 0) \
|
||||
for (bit_num_ = SBITMAP_ELT_BITS; bit_num_ > 0; bit_num_--) \
|
||||
{ \
|
||||
SBITMAP_ELT_TYPE _mask = (SBITMAP_ELT_TYPE)1 << (bit_num_ - 1);\
|
||||
\
|
||||
if ((word_ & _mask) != 0) \
|
||||
{ \
|
||||
word_ &= ~ _mask; \
|
||||
(N) = (word_num_ - 1) * SBITMAP_ELT_BITS + bit_num_ - 1;\
|
||||
CODE; \
|
||||
if (word_ == 0) \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define sbitmap_free(MAP) free(MAP)
|
||||
#define sbitmap_vector_free(VEC) free(VEC)
|
||||
|
||||
struct int_list;
|
||||
|
||||
extern void dump_sbitmap PARAMS ((FILE *, sbitmap));
|
||||
extern void dump_sbitmap_file PARAMS ((FILE *, sbitmap));
|
||||
extern void dump_sbitmap_vector PARAMS ((FILE *, const char *,
|
||||
const char *, sbitmap *,
|
||||
int));
|
||||
|
134
gcc/toplev.c
134
gcc/toplev.c
@ -95,6 +95,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
extern int size_directive_output;
|
||||
extern tree last_assemble_variable_decl;
|
||||
|
||||
extern void reg_alloc PARAMS ((void));
|
||||
|
||||
static void general_init PARAMS ((char *));
|
||||
static bool parse_options_and_default_flags PARAMS ((int, char **));
|
||||
static void do_compile PARAMS ((int));
|
||||
@ -865,6 +867,9 @@ int flag_merge_constants = 1;
|
||||
one, unconditionally renumber instruction UIDs. */
|
||||
int flag_renumber_insns = 1;
|
||||
|
||||
/* If nonzero, use the graph coloring register allocator. */
|
||||
int flag_new_regalloc = 0;
|
||||
|
||||
/* Nonzero if we perform superblock formation. */
|
||||
|
||||
int flag_tracer = 0;
|
||||
@ -1173,6 +1178,8 @@ static const lang_independent_options f_options[] =
|
||||
N_("Report on permanent memory allocation at end of run") },
|
||||
{ "trapv", &flag_trapv, 1,
|
||||
N_("Trap for signed overflow in addition / subtraction / multiplication") },
|
||||
{ "new-ra", &flag_new_regalloc, 1,
|
||||
N_("Use graph coloring register allocation.") },
|
||||
};
|
||||
|
||||
/* Table of language-specific options. */
|
||||
@ -3039,7 +3046,7 @@ rest_of_compilation (decl)
|
||||
if (optimize)
|
||||
{
|
||||
clear_bb_flags ();
|
||||
if (initialize_uninitialized_subregs ())
|
||||
if (!flag_new_regalloc && initialize_uninitialized_subregs ())
|
||||
{
|
||||
/* Insns were inserted, so things might look a bit different. */
|
||||
insns = get_insns ();
|
||||
@ -3174,61 +3181,102 @@ rest_of_compilation (decl)
|
||||
if (! register_life_up_to_date)
|
||||
recompute_reg_usage (insns, ! optimize_size);
|
||||
|
||||
/* Allocate the reg_renumber array. */
|
||||
allocate_reg_info (max_regno, FALSE, TRUE);
|
||||
|
||||
/* And the reg_equiv_memory_loc array. */
|
||||
reg_equiv_memory_loc = (rtx *) xcalloc (max_regno, sizeof (rtx));
|
||||
|
||||
allocate_initial_values (reg_equiv_memory_loc);
|
||||
|
||||
regclass (insns, max_reg_num (), rtl_dump_file);
|
||||
rebuild_label_notes_after_reload = local_alloc ();
|
||||
|
||||
timevar_pop (TV_LOCAL_ALLOC);
|
||||
|
||||
if (dump_file[DFI_lreg].enabled)
|
||||
if (flag_new_regalloc)
|
||||
{
|
||||
timevar_push (TV_DUMP);
|
||||
delete_trivially_dead_insns (insns, max_reg_num ());
|
||||
reg_alloc ();
|
||||
|
||||
dump_flow_info (rtl_dump_file);
|
||||
dump_local_alloc (rtl_dump_file);
|
||||
timevar_pop (TV_LOCAL_ALLOC);
|
||||
if (dump_file[DFI_lreg].enabled)
|
||||
{
|
||||
timevar_push (TV_DUMP);
|
||||
|
||||
close_dump_file (DFI_lreg, print_rtl_with_bb, insns);
|
||||
timevar_pop (TV_DUMP);
|
||||
}
|
||||
close_dump_file (DFI_lreg, NULL, NULL);
|
||||
timevar_pop (TV_DUMP);
|
||||
}
|
||||
|
||||
ggc_collect ();
|
||||
/* XXX clean up the whole mess to bring live info in shape again. */
|
||||
timevar_push (TV_GLOBAL_ALLOC);
|
||||
open_dump_file (DFI_greg, decl);
|
||||
|
||||
timevar_push (TV_GLOBAL_ALLOC);
|
||||
open_dump_file (DFI_greg, decl);
|
||||
|
||||
/* If optimizing, allocate remaining pseudo-regs. Do the reload
|
||||
pass fixing up any insns that are invalid. */
|
||||
|
||||
if (optimize)
|
||||
failure = global_alloc (rtl_dump_file);
|
||||
else
|
||||
{
|
||||
build_insn_chain (insns);
|
||||
failure = reload (insns, 0);
|
||||
|
||||
timevar_pop (TV_GLOBAL_ALLOC);
|
||||
|
||||
if (dump_file[DFI_greg].enabled)
|
||||
{
|
||||
timevar_push (TV_DUMP);
|
||||
|
||||
dump_global_regs (rtl_dump_file);
|
||||
|
||||
close_dump_file (DFI_greg, print_rtl_with_bb, insns);
|
||||
timevar_pop (TV_DUMP);
|
||||
}
|
||||
|
||||
if (failure)
|
||||
goto exit_rest_of_compilation;
|
||||
reload_completed = 1;
|
||||
rebuild_label_notes_after_reload = 0;
|
||||
}
|
||||
|
||||
timevar_pop (TV_GLOBAL_ALLOC);
|
||||
|
||||
if (dump_file[DFI_greg].enabled)
|
||||
else
|
||||
{
|
||||
timevar_push (TV_DUMP);
|
||||
/* Allocate the reg_renumber array. */
|
||||
allocate_reg_info (max_regno, FALSE, TRUE);
|
||||
|
||||
dump_global_regs (rtl_dump_file);
|
||||
/* And the reg_equiv_memory_loc array. */
|
||||
reg_equiv_memory_loc = (rtx *) xcalloc (max_regno, sizeof (rtx));
|
||||
|
||||
close_dump_file (DFI_greg, print_rtl_with_bb, insns);
|
||||
timevar_pop (TV_DUMP);
|
||||
allocate_initial_values (reg_equiv_memory_loc);
|
||||
|
||||
regclass (insns, max_reg_num (), rtl_dump_file);
|
||||
rebuild_label_notes_after_reload = local_alloc ();
|
||||
|
||||
timevar_pop (TV_LOCAL_ALLOC);
|
||||
|
||||
if (dump_file[DFI_lreg].enabled)
|
||||
{
|
||||
timevar_push (TV_DUMP);
|
||||
|
||||
dump_flow_info (rtl_dump_file);
|
||||
dump_local_alloc (rtl_dump_file);
|
||||
|
||||
close_dump_file (DFI_lreg, print_rtl_with_bb, insns);
|
||||
timevar_pop (TV_DUMP);
|
||||
}
|
||||
|
||||
ggc_collect ();
|
||||
|
||||
timevar_push (TV_GLOBAL_ALLOC);
|
||||
open_dump_file (DFI_greg, decl);
|
||||
|
||||
/* If optimizing, allocate remaining pseudo-regs. Do the reload
|
||||
pass fixing up any insns that are invalid. */
|
||||
|
||||
if (optimize)
|
||||
failure = global_alloc (rtl_dump_file);
|
||||
else
|
||||
{
|
||||
build_insn_chain (insns);
|
||||
failure = reload (insns, 0);
|
||||
}
|
||||
|
||||
timevar_pop (TV_GLOBAL_ALLOC);
|
||||
|
||||
if (dump_file[DFI_greg].enabled)
|
||||
{
|
||||
timevar_push (TV_DUMP);
|
||||
|
||||
dump_global_regs (rtl_dump_file);
|
||||
|
||||
close_dump_file (DFI_greg, print_rtl_with_bb, insns);
|
||||
timevar_pop (TV_DUMP);
|
||||
}
|
||||
|
||||
if (failure)
|
||||
goto exit_rest_of_compilation;
|
||||
}
|
||||
|
||||
if (failure)
|
||||
goto exit_rest_of_compilation;
|
||||
|
||||
ggc_collect ();
|
||||
|
||||
open_dump_file (DFI_postreload, decl);
|
||||
|
Loading…
x
Reference in New Issue
Block a user