Makefile.in (stupid.o): Update dependencies.
* Makefile.in (stupid.o): Update dependencies. (global.o): Likewise. * global.c: Include reload.h (reg_becomes_live): New function. (reg_dies): New function. (build_insn_chain): New function. (global_alloc): Call build_insn_chain before calling reload. * reload.h (struct needs): New structure definition. (struct insn_chain): Likewise. (reload_insn_chain): Declare variable. (new_insn_chain): Declare function. * reload1.c (reload_startobj): New variable. (reload_insn_chain): New variable. (unused_insn_chains): New variable. (new_insn_chain): New function. (init_reload): Initialize reload_startobj, not reload_firstobj. (reload): Initialize reload_firstobj. Before returning, free everything on the reload_obstack. * stupid.c: Include insn-config.h, reload.h and basic-block.h. (reg_where_dead_chain, reg_where_born_exact, reg_where_born_clobber, current_chain): New variables. (reg_where_born): Delete variable. (REG_WHERE_BORN): New macro. (find_clobbered_regs): New function. (stupid_life_analysis): Don't allocate/free reg_where_born. Allocate and free reg_where_born_exact, reg_where_born_clobber, reg_where_dead_chain. Use REG_WHERE_BORN instead of reg_where_born. While processing the insns, build the reload_insn_chain with information about register lifetimes. (stupid_reg_compare): Use REG_WHERE_BORN instead of reg_where_born. (stupid_mark_refs): Replace arg INSN with arg CHAIN. All callers changed. Compute and information about birth and death of pseudo registers in reg_where_dead_chain, reg_where_born_exact and reg_where_born_clobber. Delete code to set elements of reg_where_born. From-SVN: r22862
This commit is contained in:
parent
0eaae86cab
commit
cad6f7d050
@ -1,3 +1,47 @@
|
||||
Tue Oct 6 01:36:00 1998 Bernd Schmidt <crux@Pool.Informatik.RWTH-Aachen.DE>
|
||||
|
||||
* Makefile.in (stupid.o): Update dependencies.
|
||||
(global.o): Likewise.
|
||||
|
||||
* global.c: Include reload.h
|
||||
(reg_becomes_live): New function.
|
||||
(reg_dies): New function.
|
||||
(build_insn_chain): New function.
|
||||
(global_alloc): Call build_insn_chain before calling reload.
|
||||
|
||||
* reload.h (struct needs): New structure definition.
|
||||
(struct insn_chain): Likewise.
|
||||
(reload_insn_chain): Declare variable.
|
||||
(new_insn_chain): Declare function.
|
||||
|
||||
|
||||
* reload1.c (reload_startobj): New variable.
|
||||
(reload_insn_chain): New variable.
|
||||
(unused_insn_chains): New variable.
|
||||
(new_insn_chain): New function.
|
||||
(init_reload): Initialize reload_startobj, not reload_firstobj.
|
||||
(reload): Initialize reload_firstobj.
|
||||
Before returning, free everything on the reload_obstack.
|
||||
|
||||
* stupid.c: Include insn-config.h, reload.h and basic-block.h.
|
||||
(reg_where_dead_chain, reg_where_born_exact, reg_where_born_clobber,
|
||||
current_chain): New variables.
|
||||
(reg_where_born): Delete variable.
|
||||
(REG_WHERE_BORN): New macro.
|
||||
(find_clobbered_regs): New function.
|
||||
(stupid_life_analysis): Don't allocate/free reg_where_born.
|
||||
Allocate and free reg_where_born_exact, reg_where_born_clobber,
|
||||
reg_where_dead_chain.
|
||||
Use REG_WHERE_BORN instead of reg_where_born.
|
||||
While processing the insns, build the reload_insn_chain with
|
||||
information about register lifetimes.
|
||||
(stupid_reg_compare): Use REG_WHERE_BORN instead of reg_where_born.
|
||||
(stupid_mark_refs): Replace arg INSN with arg CHAIN. All callers
|
||||
changed.
|
||||
Compute and information about birth and death of pseudo registers in
|
||||
reg_where_dead_chain, reg_where_born_exact and reg_where_born_clobber.
|
||||
Delete code to set elements of reg_where_born.
|
||||
|
||||
Mon Oct 5 22:34:30 1998 Alexandre Petit-Bianco <apbianco@cygnus.com>
|
||||
|
||||
* tree.def (GOTO_EXPR): Modified documentation.
|
||||
|
@ -1461,7 +1461,7 @@ jump.o : jump.c $(CONFIG_H) system.h $(RTL_H) flags.h hard-reg-set.h $(REGS_H) \
|
||||
insn-config.h insn-flags.h $(RECOG_H) $(EXPR_H) real.h except.h \
|
||||
toplev.h
|
||||
stupid.o : stupid.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h \
|
||||
flags.h toplev.h
|
||||
$(BASIC_BLOCK_H) insn-config.h reload.h flags.h toplev.h
|
||||
|
||||
cse.o : cse.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \
|
||||
real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h output.h
|
||||
@ -1487,7 +1487,7 @@ local-alloc.o : local-alloc.c $(CONFIG_H) system.h $(RTL_H) flags.h \
|
||||
insn-attr.h toplev.h
|
||||
bitmap.o : bitmap.c $(CONFIG_H) system.h $(RTL_H) flags.h $(BASIC_BLOCK_H) \
|
||||
$(REGS_H)
|
||||
global.o : global.c $(CONFIG_H) system.h $(RTL_H) flags.h \
|
||||
global.o : global.c $(CONFIG_H) system.h $(RTL_H) flags.h reload.h \
|
||||
$(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h insn-config.h output.h toplev.h
|
||||
varray.o : varray.c $(CONFIG_H) system.h varray.h $(RTL_H) $(TREE_H) bitmap.h
|
||||
|
||||
|
138
gcc/global.c
138
gcc/global.c
@ -29,6 +29,7 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "basic-block.h"
|
||||
#include "regs.h"
|
||||
#include "insn-config.h"
|
||||
#include "reload.h"
|
||||
#include "output.h"
|
||||
#include "toplev.h"
|
||||
|
||||
@ -268,6 +269,9 @@ static void mark_reg_death PROTO((rtx));
|
||||
static void mark_reg_live_nc PROTO((int, enum machine_mode));
|
||||
static void set_preference PROTO((rtx, rtx));
|
||||
static void dump_conflicts PROTO((FILE *));
|
||||
static void reg_becomes_live PROTO((rtx, rtx));
|
||||
static void reg_dies PROTO((int, enum machine_mode));
|
||||
static void build_insn_chain PROTO((rtx));
|
||||
|
||||
/* Perform allocation of pseudo-registers not allocated by local_alloc.
|
||||
FILE is a file to output debugging information on,
|
||||
@ -573,7 +577,10 @@ global_alloc (file)
|
||||
for the sake of debugging information. */
|
||||
if (n_basic_blocks > 0)
|
||||
#endif
|
||||
retval = reload (get_insns (), 1, file);
|
||||
{
|
||||
build_insn_chain (get_insns ());
|
||||
retval = reload (get_insns (), 1, file);
|
||||
}
|
||||
|
||||
free (conflicts);
|
||||
return retval;
|
||||
@ -1648,6 +1655,135 @@ mark_elimination (from, to)
|
||||
}
|
||||
}
|
||||
|
||||
/* Used for communication between the following functions. Holds the
|
||||
current life information. */
|
||||
static regset live_relevant_regs;
|
||||
|
||||
/* Record in live_relevant_regs that register REG became live. This
|
||||
is called via note_stores. */
|
||||
static void
|
||||
reg_becomes_live (reg, setter)
|
||||
rtx reg;
|
||||
rtx setter ATTRIBUTE_UNUSED;
|
||||
{
|
||||
int regno;
|
||||
|
||||
if (GET_CODE (reg) == SUBREG)
|
||||
reg = SUBREG_REG (reg);
|
||||
|
||||
if (GET_CODE (reg) != REG)
|
||||
return;
|
||||
|
||||
regno = REGNO (reg);
|
||||
if (regno < FIRST_PSEUDO_REGISTER)
|
||||
{
|
||||
int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
|
||||
while (nregs-- > 0)
|
||||
SET_REGNO_REG_SET (live_relevant_regs, regno++);
|
||||
}
|
||||
else if (reg_renumber[regno] >= 0)
|
||||
SET_REGNO_REG_SET (live_relevant_regs, regno);
|
||||
}
|
||||
|
||||
/* Record in live_relevant_regs that register REGNO died. */
|
||||
static void
|
||||
reg_dies (regno, mode)
|
||||
int regno;
|
||||
enum machine_mode mode;
|
||||
{
|
||||
if (regno < FIRST_PSEUDO_REGISTER)
|
||||
{
|
||||
int nregs = HARD_REGNO_NREGS (regno, mode);
|
||||
while (nregs-- > 0)
|
||||
CLEAR_REGNO_REG_SET (live_relevant_regs, regno++);
|
||||
}
|
||||
else
|
||||
CLEAR_REGNO_REG_SET (live_relevant_regs, regno);
|
||||
}
|
||||
|
||||
/* Walk the insns of the current function and build reload_insn_chain,
|
||||
and record register life information. */
|
||||
static void
|
||||
build_insn_chain (first)
|
||||
rtx first;
|
||||
{
|
||||
struct insn_chain **p = &reload_insn_chain;
|
||||
struct insn_chain *prev = 0;
|
||||
int b = 0;
|
||||
|
||||
live_relevant_regs = ALLOCA_REG_SET ();
|
||||
|
||||
for (; first; first = NEXT_INSN (first))
|
||||
{
|
||||
struct insn_chain *c;
|
||||
|
||||
if (first == basic_block_head[b])
|
||||
{
|
||||
int i;
|
||||
CLEAR_REG_SET (live_relevant_regs);
|
||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
||||
if (REGNO_REG_SET_P (basic_block_live_at_start[b], i)
|
||||
&& ! TEST_HARD_REG_BIT (eliminable_regset, i))
|
||||
SET_REGNO_REG_SET (live_relevant_regs, i);
|
||||
|
||||
for (; i < max_regno; i++)
|
||||
if (reg_renumber[i] >= 0
|
||||
&& REGNO_REG_SET_P (basic_block_live_at_start[b], i))
|
||||
SET_REGNO_REG_SET (live_relevant_regs, i);
|
||||
}
|
||||
|
||||
if (GET_CODE (first) != NOTE && GET_CODE (first) != BARRIER)
|
||||
{
|
||||
c = new_insn_chain ();
|
||||
c->prev = prev;
|
||||
prev = c;
|
||||
*p = c;
|
||||
p = &c->next;
|
||||
c->insn = first;
|
||||
c->block = b;
|
||||
|
||||
COPY_REG_SET (c->live_before, live_relevant_regs);
|
||||
|
||||
if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
|
||||
{
|
||||
rtx link;
|
||||
|
||||
/* Mark the death of everything that dies in this instruction. */
|
||||
|
||||
for (link = REG_NOTES (first); link; link = XEXP (link, 1))
|
||||
if (REG_NOTE_KIND (link) == REG_DEAD
|
||||
&& GET_CODE (XEXP (link, 0)) == REG)
|
||||
reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)));
|
||||
|
||||
/* Mark everything born in this instruction as live. */
|
||||
|
||||
note_stores (PATTERN (first), reg_becomes_live);
|
||||
}
|
||||
|
||||
/* Remember which registers are live at the end of the insn, before
|
||||
killing those with REG_UNUSED notes. */
|
||||
COPY_REG_SET (c->live_after, live_relevant_regs);
|
||||
|
||||
if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
|
||||
{
|
||||
rtx link;
|
||||
|
||||
/* Mark anything that is set in this insn and then unused as dying. */
|
||||
|
||||
for (link = REG_NOTES (first); link; link = XEXP (link, 1))
|
||||
if (REG_NOTE_KIND (link) == REG_UNUSED
|
||||
&& GET_CODE (XEXP (link, 0)) == REG)
|
||||
reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)));
|
||||
}
|
||||
}
|
||||
|
||||
if (first == basic_block_end[b])
|
||||
b++;
|
||||
}
|
||||
FREE_REG_SET (live_relevant_regs);
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
/* Print debugging trace information if -greg switch is given,
|
||||
showing the information on which the allocation decisions are based. */
|
||||
|
||||
|
75
gcc/reload.h
75
gcc/reload.h
@ -142,6 +142,81 @@ extern enum insn_code reload_in_optab[];
|
||||
extern enum insn_code reload_out_optab[];
|
||||
#endif
|
||||
|
||||
struct needs
|
||||
{
|
||||
/* [0] is normal, [1] is nongroup. */
|
||||
short regs[2][N_REG_CLASSES];
|
||||
short groups[N_REG_CLASSES];
|
||||
};
|
||||
|
||||
#if defined SET_HARD_REG_BIT && defined CLEAR_REG_SET
|
||||
/* This structure describes instructions which are relevant for reload.
|
||||
Apart from all regular insns, this also includes CODE_LABELs, since they
|
||||
must be examined for register elimination. */
|
||||
struct insn_chain
|
||||
{
|
||||
/* Links to the neighbour instructions. */
|
||||
struct insn_chain *next, *prev;
|
||||
|
||||
/* Link through a chains set up by calculate_needs_all_insns, containing
|
||||
all insns that need reloading. */
|
||||
struct insn_chain *next_need_reload;
|
||||
|
||||
/* The basic block this insn is in. */
|
||||
int block;
|
||||
/* The rtx of the insn. */
|
||||
rtx insn;
|
||||
/* Register life information: record all live hard registers, and all
|
||||
live pseudos that have a hard register.
|
||||
This information is recorded for the point immediately before the insn
|
||||
(in live_before), and for the point within the insn at which all
|
||||
outputs have just been written to (in live_after). */
|
||||
regset live_before;
|
||||
regset live_after;
|
||||
|
||||
/* For each class, size of group of consecutive regs
|
||||
that is needed for the reloads of this class. */
|
||||
char group_size[N_REG_CLASSES];
|
||||
/* For each class, the machine mode which requires consecutive
|
||||
groups of regs of that class.
|
||||
If two different modes ever require groups of one class,
|
||||
they must be the same size and equally restrictive for that class,
|
||||
otherwise we can't handle the complexity. */
|
||||
enum machine_mode group_mode[N_REG_CLASSES];
|
||||
|
||||
/* Indicates if a register was counted against the need for
|
||||
groups. 0 means it can count against max_nongroup instead. */
|
||||
HARD_REG_SET counted_for_groups;
|
||||
|
||||
/* Indicates if a register was counted against the need for
|
||||
non-groups. 0 means it can become part of a new group.
|
||||
During choose_reload_regs, 1 here means don't use this reg
|
||||
as part of a group, even if it seems to be otherwise ok. */
|
||||
HARD_REG_SET counted_for_nongroups;
|
||||
|
||||
/* Indicates which registers have already been used for spills. */
|
||||
HARD_REG_SET used_spill_regs;
|
||||
|
||||
/* Describe the needs for reload registers of this insn. */
|
||||
struct needs need;
|
||||
|
||||
/* Nonzero if find_reloads said the insn requires reloading. */
|
||||
unsigned int need_reload:1;
|
||||
/* Nonzero if eliminate_regs_in_insn said it requires eliminations. */
|
||||
unsigned int need_elim:1;
|
||||
/* Nonzero if this insn was inserted by perform_caller_saves. */
|
||||
unsigned int is_caller_save_insn:1;
|
||||
};
|
||||
|
||||
/* A chain of insn_chain structures to describe all non-note insns in
|
||||
a function. */
|
||||
extern struct insn_chain *reload_insn_chain;
|
||||
|
||||
/* Allocate a new insn_chain structure. */
|
||||
extern struct insn_chain *new_insn_chain PROTO((void));
|
||||
|
||||
#endif
|
||||
|
||||
/* Functions from reload.c: */
|
||||
|
||||
/* Return a memory location that will be used to copy X in mode MODE.
|
||||
|
@ -32,9 +32,9 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "flags.h"
|
||||
#include "expr.h"
|
||||
#include "regs.h"
|
||||
#include "basic-block.h"
|
||||
#include "reload.h"
|
||||
#include "recog.h"
|
||||
#include "basic-block.h"
|
||||
#include "output.h"
|
||||
#include "real.h"
|
||||
#include "toplev.h"
|
||||
@ -279,6 +279,13 @@ enum insn_code reload_out_optab[NUM_MACHINE_MODES];
|
||||
insn. */
|
||||
|
||||
struct obstack reload_obstack;
|
||||
|
||||
/* Points to the beginning of the reload_obstack. All insn_chain structures
|
||||
are allocated first. */
|
||||
char *reload_startobj;
|
||||
|
||||
/* The point after all insn_chain structures. Used to quickly deallocate
|
||||
memory used while processing one insn. */
|
||||
char *reload_firstobj;
|
||||
|
||||
#define obstack_chunk_alloc xmalloc
|
||||
@ -286,6 +293,10 @@ char *reload_firstobj;
|
||||
|
||||
/* List of labels that must never be deleted. */
|
||||
extern rtx forced_labels;
|
||||
|
||||
/* List of insn_chain instructions, one for every insn that reload needs to
|
||||
examine. */
|
||||
struct insn_chain *reload_insn_chain;
|
||||
|
||||
/* This structure is used to record information about register eliminations.
|
||||
Each array entry describes one possible way of eliminating a register
|
||||
@ -461,7 +472,7 @@ init_reload ()
|
||||
|
||||
/* Initialize obstack for our rtl allocation. */
|
||||
gcc_obstack_init (&reload_obstack);
|
||||
reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
|
||||
reload_startobj = (char *) obstack_alloc (&reload_obstack, 0);
|
||||
|
||||
/* Decide which register class should be used when reloading
|
||||
addresses. If we are using SMALL_REGISTER_CLASSES, and any
|
||||
@ -522,6 +533,32 @@ init_reload ()
|
||||
}
|
||||
}
|
||||
|
||||
/* List of insn chains that are currently unused. */
|
||||
static struct insn_chain *unused_insn_chains = 0;
|
||||
|
||||
/* Allocate an empty insn_chain structure. */
|
||||
struct insn_chain *
|
||||
new_insn_chain ()
|
||||
{
|
||||
struct insn_chain *c;
|
||||
|
||||
if (unused_insn_chains == 0)
|
||||
{
|
||||
c = obstack_alloc (&reload_obstack, sizeof (struct insn_chain));
|
||||
c->live_before = OBSTACK_ALLOC_REG_SET (&reload_obstack);
|
||||
c->live_after = OBSTACK_ALLOC_REG_SET (&reload_obstack);
|
||||
}
|
||||
else
|
||||
{
|
||||
c = unused_insn_chains;
|
||||
unused_insn_chains = c->next;
|
||||
}
|
||||
c->is_caller_save_insn = 0;
|
||||
c->need_reload = 0;
|
||||
c->need_elim = 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Global variables used by reload and its subroutines. */
|
||||
|
||||
/* Set during calculate_needs if an insn needs reloading. */
|
||||
@ -605,6 +642,8 @@ reload (first, global, dumpfile)
|
||||
|
||||
failure = 0;
|
||||
|
||||
reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
|
||||
|
||||
/* Enable find_equiv_reg to distinguish insns made by reload. */
|
||||
reload_first_uid = get_max_uid ();
|
||||
|
||||
@ -1217,7 +1256,9 @@ reload (first, global, dumpfile)
|
||||
if (size > STACK_CHECK_MAX_FRAME_SIZE)
|
||||
warning ("frame size too large for reliable stack checking");
|
||||
}
|
||||
|
||||
|
||||
obstack_free (&reload_obstack, reload_startobj);
|
||||
|
||||
/* Indicate that we no longer have known memory locations or constants. */
|
||||
reg_equiv_constant = 0;
|
||||
reg_equiv_memory_loc = 0;
|
||||
|
175
gcc/stupid.c
175
gcc/stupid.c
@ -47,7 +47,10 @@ Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "rtl.h"
|
||||
#include "hard-reg-set.h"
|
||||
#include "basic-block.h"
|
||||
#include "regs.h"
|
||||
#include "insn-config.h"
|
||||
#include "reload.h"
|
||||
#include "flags.h"
|
||||
#include "toplev.h"
|
||||
|
||||
@ -77,9 +80,21 @@ static int last_setjmp_suid;
|
||||
|
||||
static int *reg_where_dead;
|
||||
|
||||
/* Element N is suid of insn where life span of pseudo reg N begins. */
|
||||
/* Likewise, but point to the insn_chain structure of the insn at which
|
||||
the reg dies. */
|
||||
static struct insn_chain **reg_where_dead_chain;
|
||||
|
||||
static int *reg_where_born;
|
||||
/* Element N is suid of insn where life span of pseudo reg N begins. */
|
||||
static int *reg_where_born_exact;
|
||||
|
||||
/* Element N is 1 if the birth of pseudo reg N is due to a CLOBBER,
|
||||
0 otherwise. */
|
||||
static int *reg_where_born_clobber;
|
||||
|
||||
/* Return the suid of the insn where the register is born, or the suid
|
||||
of the insn before if the birth is due to a CLOBBER. */
|
||||
#define REG_WHERE_BORN(N) \
|
||||
(reg_where_born_exact[(N)] - reg_where_born_clobber[(N)])
|
||||
|
||||
/* Numbers of pseudo-regs to be allocated, highest priority first. */
|
||||
|
||||
@ -111,7 +126,43 @@ static HARD_REG_SET *after_insn_hard_regs;
|
||||
static int stupid_reg_compare PROTO((const GENERIC_PTR,const GENERIC_PTR));
|
||||
static int stupid_find_reg PROTO((int, enum reg_class, enum machine_mode,
|
||||
int, int, int));
|
||||
static void stupid_mark_refs PROTO((rtx, rtx));
|
||||
static void stupid_mark_refs PROTO((rtx, struct insn_chain *));
|
||||
static void find_clobbered_regs PROTO((rtx, rtx));
|
||||
|
||||
/* For communication between stupid_life_analysis and find_clobbered_regs. */
|
||||
static struct insn_chain *current_chain;
|
||||
|
||||
/* This function, called via note_stores, marks any hard registers that are
|
||||
clobbered in an insn as being live in the live_after and live_before fields
|
||||
of the appropriate insn_chain structure. */
|
||||
|
||||
static void
|
||||
find_clobbered_regs (reg, setter)
|
||||
rtx reg, setter;
|
||||
{
|
||||
int regno, nregs;
|
||||
if (setter == 0 || GET_CODE (setter) != CLOBBER)
|
||||
return;
|
||||
|
||||
if (GET_CODE (reg) == SUBREG)
|
||||
reg = SUBREG_REG (reg);
|
||||
|
||||
if (GET_CODE (reg) != REG)
|
||||
return;
|
||||
regno = REGNO (reg);
|
||||
if (regno >= FIRST_PSEUDO_REGISTER)
|
||||
return;
|
||||
|
||||
if (GET_MODE (reg) == VOIDmode)
|
||||
abort ();
|
||||
else
|
||||
nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
|
||||
while (nregs-- > 0)
|
||||
{
|
||||
SET_REGNO_REG_SET (current_chain->live_after, regno);
|
||||
SET_REGNO_REG_SET (current_chain->live_before, regno++);
|
||||
}
|
||||
}
|
||||
|
||||
/* Stupid life analysis is for the case where only variables declared
|
||||
`register' go in registers. For this case, we mark all
|
||||
@ -171,9 +222,15 @@ stupid_life_analysis (f, nregs, file)
|
||||
reg_where_dead = (int *) xmalloc (nregs * sizeof (int));
|
||||
bzero ((char *) reg_where_dead, nregs * sizeof (int));
|
||||
|
||||
reg_where_born = (int *) xmalloc (nregs * sizeof (int));
|
||||
bzero ((char *) reg_where_born, nregs * sizeof (int));
|
||||
reg_where_born_exact = (int *) xmalloc (nregs * sizeof (int));
|
||||
bzero ((char *) reg_where_born_exact, nregs * sizeof (int));
|
||||
|
||||
reg_where_born_clobber = (int *) xmalloc (nregs * sizeof (int));
|
||||
bzero ((char *) reg_where_born_clobber, nregs * sizeof (int));
|
||||
|
||||
reg_where_dead_chain = (struct insn_chain **) xmalloc (nregs * sizeof (struct insn_chain *));
|
||||
bzero ((char *) reg_where_dead_chain, nregs * sizeof (struct insn_chain *));
|
||||
|
||||
reg_order = (int *) xmalloc (nregs * sizeof (int));
|
||||
bzero ((char *) reg_order, nregs * sizeof (int));
|
||||
|
||||
@ -210,11 +267,15 @@ stupid_life_analysis (f, nregs, file)
|
||||
Also find where each hard register is live
|
||||
and record that info in after_insn_hard_regs.
|
||||
regs_live[I] is 1 if hard reg I is live
|
||||
at the current point in the scan. */
|
||||
at the current point in the scan.
|
||||
|
||||
Build reload_insn_chain while we're walking the insns. */
|
||||
|
||||
reload_insn_chain = 0;
|
||||
for (insn = last; insn; insn = PREV_INSN (insn))
|
||||
{
|
||||
register HARD_REG_SET *p = after_insn_hard_regs + INSN_SUID (insn);
|
||||
struct insn_chain *chain;
|
||||
|
||||
/* Copy the info in regs_live into the element of after_insn_hard_regs
|
||||
for the current position in the rtl code. */
|
||||
@ -223,12 +284,27 @@ stupid_life_analysis (f, nregs, file)
|
||||
if (regs_live[i])
|
||||
SET_HARD_REG_BIT (*p, i);
|
||||
|
||||
if (GET_CODE (insn) != NOTE && GET_CODE (insn) != BARRIER)
|
||||
{
|
||||
chain = new_insn_chain ();
|
||||
if (reload_insn_chain)
|
||||
reload_insn_chain->prev = chain;
|
||||
chain->next = reload_insn_chain;
|
||||
chain->prev = 0;
|
||||
reload_insn_chain = chain;
|
||||
chain->block = 0;
|
||||
chain->insn = insn;
|
||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
||||
if (regs_live[i])
|
||||
SET_REGNO_REG_SET (chain->live_before, i);
|
||||
}
|
||||
|
||||
/* Update which hard regs are currently live
|
||||
and also the birth and death suids of pseudo regs
|
||||
based on the pattern of this insn. */
|
||||
|
||||
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
|
||||
stupid_mark_refs (PATTERN (insn), insn);
|
||||
stupid_mark_refs (PATTERN (insn), chain);
|
||||
|
||||
if (GET_CODE (insn) == NOTE
|
||||
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
|
||||
@ -266,8 +342,23 @@ stupid_life_analysis (f, nregs, file)
|
||||
/* It is important that this be done after processing the insn's
|
||||
pattern because we want the function result register to still
|
||||
be live if it's also used to pass arguments. */
|
||||
stupid_mark_refs (CALL_INSN_FUNCTION_USAGE (insn), insn);
|
||||
stupid_mark_refs (CALL_INSN_FUNCTION_USAGE (insn), chain);
|
||||
}
|
||||
|
||||
if (GET_CODE (insn) != NOTE && GET_CODE (insn) != BARRIER)
|
||||
{
|
||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
||||
if (regs_live[i])
|
||||
SET_REGNO_REG_SET (chain->live_after, i);
|
||||
|
||||
/* The regs_live array doesn't say anything about hard registers
|
||||
clobbered by this insn. So we need an extra pass over the
|
||||
pattern. */
|
||||
current_chain = chain;
|
||||
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
|
||||
note_stores (PATTERN (insn), find_clobbered_regs);
|
||||
}
|
||||
|
||||
if (GET_CODE (insn) == JUMP_INSN && computed_jump_p (insn))
|
||||
current_function_has_computed_jump = 1;
|
||||
}
|
||||
@ -289,8 +380,10 @@ stupid_life_analysis (f, nregs, file)
|
||||
|
||||
/* Some regnos disappear from the rtl. Ignore them to avoid crash.
|
||||
Also don't allocate registers that cross a setjmp, or live across
|
||||
a call if this function receives a nonlocal goto. */
|
||||
a call if this function receives a nonlocal goto.
|
||||
Also ignore registers we didn't see during the scan. */
|
||||
if (regno_reg_rtx[r] == 0 || regs_crosses_setjmp[r]
|
||||
|| (reg_where_born_exact[r] == 0 && reg_where_dead[r] == 0)
|
||||
|| (REG_N_CALLS_CROSSED (r) > 0
|
||||
&& current_function_has_nonlocal_label))
|
||||
continue;
|
||||
@ -300,7 +393,7 @@ stupid_life_analysis (f, nregs, file)
|
||||
reg_renumber[r] = stupid_find_reg (REG_N_CALLS_CROSSED (r),
|
||||
reg_preferred_class (r),
|
||||
PSEUDO_REGNO_MODE (r),
|
||||
reg_where_born[r],
|
||||
REG_WHERE_BORN (r),
|
||||
reg_where_dead[r],
|
||||
regs_change_size[r]);
|
||||
|
||||
@ -309,18 +402,48 @@ stupid_life_analysis (f, nregs, file)
|
||||
reg_renumber[r] = stupid_find_reg (REG_N_CALLS_CROSSED (r),
|
||||
reg_alternate_class (r),
|
||||
PSEUDO_REGNO_MODE (r),
|
||||
reg_where_born[r],
|
||||
REG_WHERE_BORN (r),
|
||||
reg_where_dead[r],
|
||||
regs_change_size[r]);
|
||||
}
|
||||
|
||||
/* Fill in the pseudo reg life information into the insn chain. */
|
||||
for (i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
|
||||
{
|
||||
struct insn_chain *chain;
|
||||
int regno;
|
||||
|
||||
regno = reg_renumber[i];
|
||||
if (regno < 0)
|
||||
continue;
|
||||
|
||||
chain = reg_where_dead_chain[i];
|
||||
if (reg_where_dead[i] > INSN_SUID (chain->insn))
|
||||
SET_REGNO_REG_SET (chain->live_after, i);
|
||||
|
||||
while (INSN_SUID (chain->insn) > reg_where_born_exact[i])
|
||||
{
|
||||
SET_REGNO_REG_SET (chain->live_before, i);
|
||||
chain = chain->prev;
|
||||
if (!chain)
|
||||
break;
|
||||
SET_REGNO_REG_SET (chain->live_after, i);
|
||||
}
|
||||
|
||||
if (INSN_SUID (chain->insn) == reg_where_born_exact[i]
|
||||
&& reg_where_born_clobber[i])
|
||||
SET_REGNO_REG_SET (chain->live_before, i);
|
||||
}
|
||||
|
||||
if (file)
|
||||
dump_flow_info (file);
|
||||
|
||||
free (regs_live);
|
||||
free (uid_suid);
|
||||
free (reg_where_dead);
|
||||
free (reg_where_born);
|
||||
free (reg_where_born_exact);
|
||||
free (reg_where_born_clobber);
|
||||
free (reg_where_dead_chain);
|
||||
free (reg_order);
|
||||
free (regs_change_size);
|
||||
free (regs_crosses_setjmp);
|
||||
@ -336,8 +459,8 @@ stupid_reg_compare (r1p, r2p)
|
||||
const GENERIC_PTR r2p;
|
||||
{
|
||||
register int r1 = *(int *)r1p, r2 = *(int *)r2p;
|
||||
register int len1 = reg_where_dead[r1] - reg_where_born[r1];
|
||||
register int len2 = reg_where_dead[r2] - reg_where_born[r2];
|
||||
register int len1 = reg_where_dead[r1] - REG_WHERE_BORN (r1);
|
||||
register int len2 = reg_where_dead[r2] - REG_WHERE_BORN (r2);
|
||||
int tem;
|
||||
|
||||
tem = len2 - len1;
|
||||
@ -470,12 +593,14 @@ stupid_find_reg (call_preserved, class, mode,
|
||||
INSN is the current insn, supplied so we can find its suid. */
|
||||
|
||||
static void
|
||||
stupid_mark_refs (x, insn)
|
||||
rtx x, insn;
|
||||
stupid_mark_refs (x, chain)
|
||||
rtx x;
|
||||
struct insn_chain *chain;
|
||||
{
|
||||
register RTX_CODE code;
|
||||
register char *fmt;
|
||||
register int regno, i;
|
||||
rtx insn = chain->insn;
|
||||
|
||||
if (x == 0)
|
||||
return;
|
||||
@ -530,7 +655,11 @@ stupid_mark_refs (x, insn)
|
||||
the clobbering insn. When setting, just after. */
|
||||
int where_born = INSN_SUID (insn) - (code == CLOBBER);
|
||||
|
||||
reg_where_born[regno] = where_born;
|
||||
reg_where_born_exact[regno] = INSN_SUID (insn);
|
||||
reg_where_born_clobber[regno] = (code == CLOBBER);
|
||||
|
||||
if (reg_where_dead_chain[regno] == 0)
|
||||
reg_where_dead_chain[regno] = chain;
|
||||
|
||||
/* The reg must live at least one insn even
|
||||
in it is never again used--because it has to go
|
||||
@ -573,9 +702,9 @@ stupid_mark_refs (x, insn)
|
||||
If setting a SUBREG, we treat the entire reg as *used*. */
|
||||
if (code == SET)
|
||||
{
|
||||
stupid_mark_refs (SET_SRC (x), insn);
|
||||
stupid_mark_refs (SET_SRC (x), chain);
|
||||
if (GET_CODE (SET_DEST (x)) != REG)
|
||||
stupid_mark_refs (SET_DEST (x), insn);
|
||||
stupid_mark_refs (SET_DEST (x), chain);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -608,12 +737,14 @@ stupid_mark_refs (x, insn)
|
||||
{
|
||||
/* Pseudo reg: record first use, last use and number of uses. */
|
||||
|
||||
reg_where_born[regno] = INSN_SUID (insn);
|
||||
reg_where_born_exact[regno] = INSN_SUID (insn);
|
||||
reg_where_born_clobber[regno] = 0;
|
||||
REG_N_REFS (regno)++;
|
||||
if (regs_live[regno] == 0)
|
||||
{
|
||||
regs_live[regno] = 1;
|
||||
reg_where_dead[regno] = INSN_SUID (insn);
|
||||
reg_where_dead_chain[regno] = chain;
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -625,12 +756,12 @@ stupid_mark_refs (x, insn)
|
||||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||||
{
|
||||
if (fmt[i] == 'e')
|
||||
stupid_mark_refs (XEXP (x, i), insn);
|
||||
stupid_mark_refs (XEXP (x, i), chain);
|
||||
if (fmt[i] == 'E')
|
||||
{
|
||||
register int j;
|
||||
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
|
||||
stupid_mark_refs (XVECEXP (x, i, j), insn);
|
||||
stupid_mark_refs (XVECEXP (x, i, j), chain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user