Commit cad6f7d0 by Bernd Schmidt Committed by Jeff Law

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
parent 0eaae86c
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> Mon Oct 5 22:34:30 1998 Alexandre Petit-Bianco <apbianco@cygnus.com>
* tree.def (GOTO_EXPR): Modified documentation. * 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) \ ...@@ -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 \ insn-config.h insn-flags.h $(RECOG_H) $(EXPR_H) real.h except.h \
toplev.h toplev.h
stupid.o : stupid.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.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 \ 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 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 \ ...@@ -1487,7 +1487,7 @@ local-alloc.o : local-alloc.c $(CONFIG_H) system.h $(RTL_H) flags.h \
insn-attr.h toplev.h insn-attr.h toplev.h
bitmap.o : bitmap.c $(CONFIG_H) system.h $(RTL_H) flags.h $(BASIC_BLOCK_H) \ bitmap.o : bitmap.c $(CONFIG_H) system.h $(RTL_H) flags.h $(BASIC_BLOCK_H) \
$(REGS_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 $(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 varray.o : varray.c $(CONFIG_H) system.h varray.h $(RTL_H) $(TREE_H) bitmap.h
......
...@@ -29,6 +29,7 @@ Boston, MA 02111-1307, USA. */ ...@@ -29,6 +29,7 @@ Boston, MA 02111-1307, USA. */
#include "basic-block.h" #include "basic-block.h"
#include "regs.h" #include "regs.h"
#include "insn-config.h" #include "insn-config.h"
#include "reload.h"
#include "output.h" #include "output.h"
#include "toplev.h" #include "toplev.h"
...@@ -268,6 +269,9 @@ static void mark_reg_death PROTO((rtx)); ...@@ -268,6 +269,9 @@ static void mark_reg_death PROTO((rtx));
static void mark_reg_live_nc PROTO((int, enum machine_mode)); static void mark_reg_live_nc PROTO((int, enum machine_mode));
static void set_preference PROTO((rtx, rtx)); static void set_preference PROTO((rtx, rtx));
static void dump_conflicts PROTO((FILE *)); 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. /* Perform allocation of pseudo-registers not allocated by local_alloc.
FILE is a file to output debugging information on, FILE is a file to output debugging information on,
...@@ -573,7 +577,10 @@ global_alloc (file) ...@@ -573,7 +577,10 @@ global_alloc (file)
for the sake of debugging information. */ for the sake of debugging information. */
if (n_basic_blocks > 0) if (n_basic_blocks > 0)
#endif #endif
retval = reload (get_insns (), 1, file); {
build_insn_chain (get_insns ());
retval = reload (get_insns (), 1, file);
}
free (conflicts); free (conflicts);
return retval; return retval;
...@@ -1648,6 +1655,135 @@ mark_elimination (from, to) ...@@ -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, /* Print debugging trace information if -greg switch is given,
showing the information on which the allocation decisions are based. */ showing the information on which the allocation decisions are based. */
......
...@@ -142,6 +142,81 @@ extern enum insn_code reload_in_optab[]; ...@@ -142,6 +142,81 @@ extern enum insn_code reload_in_optab[];
extern enum insn_code reload_out_optab[]; extern enum insn_code reload_out_optab[];
#endif #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: */ /* Functions from reload.c: */
/* Return a memory location that will be used to copy X in mode MODE. /* Return a memory location that will be used to copy X in mode MODE.
......
...@@ -32,9 +32,9 @@ Boston, MA 02111-1307, USA. */ ...@@ -32,9 +32,9 @@ Boston, MA 02111-1307, USA. */
#include "flags.h" #include "flags.h"
#include "expr.h" #include "expr.h"
#include "regs.h" #include "regs.h"
#include "basic-block.h"
#include "reload.h" #include "reload.h"
#include "recog.h" #include "recog.h"
#include "basic-block.h"
#include "output.h" #include "output.h"
#include "real.h" #include "real.h"
#include "toplev.h" #include "toplev.h"
...@@ -279,6 +279,13 @@ enum insn_code reload_out_optab[NUM_MACHINE_MODES]; ...@@ -279,6 +279,13 @@ enum insn_code reload_out_optab[NUM_MACHINE_MODES];
insn. */ insn. */
struct obstack reload_obstack; 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; char *reload_firstobj;
#define obstack_chunk_alloc xmalloc #define obstack_chunk_alloc xmalloc
...@@ -286,6 +293,10 @@ char *reload_firstobj; ...@@ -286,6 +293,10 @@ char *reload_firstobj;
/* List of labels that must never be deleted. */ /* List of labels that must never be deleted. */
extern rtx forced_labels; 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. /* This structure is used to record information about register eliminations.
Each array entry describes one possible way of eliminating a register Each array entry describes one possible way of eliminating a register
...@@ -461,7 +472,7 @@ init_reload () ...@@ -461,7 +472,7 @@ init_reload ()
/* Initialize obstack for our rtl allocation. */ /* Initialize obstack for our rtl allocation. */
gcc_obstack_init (&reload_obstack); 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 /* Decide which register class should be used when reloading
addresses. If we are using SMALL_REGISTER_CLASSES, and any addresses. If we are using SMALL_REGISTER_CLASSES, and any
...@@ -522,6 +533,32 @@ init_reload () ...@@ -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. */ /* Global variables used by reload and its subroutines. */
/* Set during calculate_needs if an insn needs reloading. */ /* Set during calculate_needs if an insn needs reloading. */
...@@ -605,6 +642,8 @@ reload (first, global, dumpfile) ...@@ -605,6 +642,8 @@ reload (first, global, dumpfile)
failure = 0; failure = 0;
reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
/* Enable find_equiv_reg to distinguish insns made by reload. */ /* Enable find_equiv_reg to distinguish insns made by reload. */
reload_first_uid = get_max_uid (); reload_first_uid = get_max_uid ();
...@@ -1217,7 +1256,9 @@ reload (first, global, dumpfile) ...@@ -1217,7 +1256,9 @@ reload (first, global, dumpfile)
if (size > STACK_CHECK_MAX_FRAME_SIZE) if (size > STACK_CHECK_MAX_FRAME_SIZE)
warning ("frame size too large for reliable stack checking"); 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. */ /* Indicate that we no longer have known memory locations or constants. */
reg_equiv_constant = 0; reg_equiv_constant = 0;
reg_equiv_memory_loc = 0; reg_equiv_memory_loc = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment