Commit 5ece9746 by Jeffrey A Law Committed by Jeff Law

haifa-sched.c (build_jmp_edges): Delete dead function.

        * haifa-sched.c (build_jmp_edges): Delete dead function.
        (build_control_flow): Use cfg routines from flow.c
        (schedule_insns): Remove debugging code accidentally checked
        in earlier today.
        * basic-block.h: Add external integer list structures, typdefs,
        accessor macros and function declarations.  Simlarly for
        basic block pred/succ support and simple bitmap stuff.
        * flow.c: Add functions for integer list, basic block pred/succ
        support and simple bitmap support.
        (compute_dominators): New function to compute dominators and
        post dominators.
        (find_basic_blocks): Split into two functions.
        (life_analysis): Likewise.
        (flow_analysis): Removed.  Now handled by calling find_basic_blocks,
        the life_analysis from toplev.c
        * toplev.c (rest_of_compilation): Call find_basic_blocks, then
        life_analysis instead of flow_analysis.

Co-Authored-By: Doug Evans <devans@cygnus.com>

From-SVN: r18421
parent ac9b3c97
Thu Mar 5 23:24:50 1998 Jeffrey A Law (law@cygnus.com)
Doug Evans (devans@cygnus.com)
* haifa-sched.c (build_jmp_edges): Delete dead function.
(build_control_flow): Use cfg routines from flow.c
(schedule_insns): Remove debugging code accidentally checked
in earlier today.
* basic-block.h: Add external integer list structures, typdefs,
accessor macros and function declarations. Simlarly for
basic block pred/succ support and simple bitmap stuff.
* flow.c: Add functions for integer list, basic block pred/succ
support and simple bitmap support.
(compute_dominators): New function to compute dominators and
post dominators.
(find_basic_blocks): Split into two functions.
(life_analysis): Likewise.
(flow_analysis): Removed. Now handled by calling find_basic_blocks,
the life_analysis from toplev.c
* toplev.c (rest_of_compilation): Call find_basic_blocks, then
life_analysis instead of flow_analysis.
Thu Mar 5 23:06:26 1998 J"orn Rennecke <amylaar@cygnus.co.uk> Thu Mar 5 23:06:26 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
* jump.c (jump_optimize): Call mark_jump_label also for deleted * jump.c (jump_optimize): Call mark_jump_label also for deleted
......
...@@ -128,3 +128,124 @@ extern regset regs_live_at_setjmp; ...@@ -128,3 +128,124 @@ extern regset regs_live_at_setjmp;
#define REG_BLOCK_GLOBAL -2 #define REG_BLOCK_GLOBAL -2
#define REG_BASIC_BLOCK(N) (reg_n_info[(N)].basic_block) #define REG_BASIC_BLOCK(N) (reg_n_info[(N)].basic_block)
/* List of integers.
These are used for storing things like predecessors, etc.
This scheme isn't very space efficient, especially on 64 bit machines.
The interface is designed so that the implementation can be replaced with
something more efficient if desirable. */
typedef struct int_list {
struct int_list *next;
int val;
} int_list;
typedef int_list *int_list_ptr;
/* Integer list elements are allocated in blocks to reduce the frequency
of calls to malloc and to reduce the associated space overhead. */
typedef struct int_list_block {
struct int_list_block *next;
int nodes_left;
#define INT_LIST_NODES_IN_BLK 500
struct int_list nodes[INT_LIST_NODES_IN_BLK];
} int_list_block;
/* Given a pointer to the list, return pointer to first element. */
#define INT_LIST_FIRST(il) (il)
/* Given a pointer to a list element, return pointer to next element. */
#define INT_LIST_NEXT(p) ((p)->next)
/* Return non-zero if P points to the end of the list. */
#define INT_LIST_END(p) ((p) == NULL)
/* Return element pointed to by P. */
#define INT_LIST_VAL(p) ((p)->val)
#define INT_LIST_SET_VAL(p, new_val) ((p)->val = (new_val))
extern void free_int_list PROTO ((int_list_block **));
/* Stuff for recording basic block info. */
#define BLOCK_HEAD(B) basic_block_head[(B)]
#define BLOCK_END(B) basic_block_end[(B)]
/* Special block numbers [markers] for entry and exit. */
#define ENTRY_BLOCK (-1)
#define EXIT_BLOCK (-2)
/* from flow.c */
extern int *uid_block_number;
#define BLOCK_NUM(INSN) uid_block_number[INSN_UID (INSN)]
extern int compute_preds_succs PROTO ((int_list_ptr *, int_list_ptr *,
int *, int *));
extern void dump_bb_data PROTO ((FILE *, int_list_ptr *, int_list_ptr *));
extern void free_bb_mem PROTO ((void));
/* Simple bitmaps.
It's not clear yet whether using bitmap.[ch] will be a win.
It should be straightforward to convert so for now we keep things simple
while more important issues are dealt with. */
#define SBITMAP_ELT_BITS HOST_BITS_PER_WIDE_INT
#define SBITMAP_ELT_TYPE unsigned HOST_WIDE_INT
typedef struct simple_bitmap_def {
/* Number of bits. */
int n_bits;
/* Size in elements. */
int size;
/* Size in bytes. */
int bytes;
/* The elements. */
SBITMAP_ELT_TYPE elms[1];
} *sbitmap;
typedef SBITMAP_ELT_TYPE *sbitmap_ptr;
/* Return the set size needed for N elements. */
#define SBITMAP_SET_SIZE(n) (((n) + SBITMAP_ELT_BITS - 1) / SBITMAP_ELT_BITS)
/* set bit number bitno in the bitmap */
#define SET_BIT(bitmap, bitno) \
do { \
(bitmap)->elms [(bitno) / SBITMAP_ELT_BITS] |= (SBITMAP_ELT_TYPE) 1 << (bitno) % SBITMAP_ELT_BITS; \
} while (0)
/* test if bit number bitno in the bitmap is set */
#define TEST_BIT(bitmap, bitno) \
((bitmap)->elms [(bitno) / SBITMAP_ELT_BITS] & ((SBITMAP_ELT_TYPE) 1 << (bitno) % SBITMAP_ELT_BITS))
/* reset bit number bitno in the bitmap */
#define RESET_BIT(bitmap, bitno) \
do { \
(bitmap)->elms [(bitno) / SBITMAP_ELT_BITS] &= ~((SBITMAP_ELT_TYPE) 1 << (bitno) % SBITMAP_ELT_BITS); \
} while (0)
extern sbitmap sbitmap_alloc PROTO ((int));
extern sbitmap *sbitmap_vector_alloc PROTO ((int, int));
extern void sbitmap_copy PROTO ((sbitmap, sbitmap));
extern void sbitmap_zero PROTO ((sbitmap));
extern void sbitmap_ones PROTO ((sbitmap));
extern void sbitmap_vector_zero PROTO ((sbitmap *, int));
extern void sbitmap_vector_ones PROTO ((sbitmap *, int));
extern int sbitmap_union_of_diff PROTO ((sbitmap, sbitmap, sbitmap, sbitmap));
extern void sbitmap_difference PROTO ((sbitmap, sbitmap, sbitmap));
extern void sbitmap_not PROTO ((sbitmap, sbitmap));
extern int sbitmap_a_or_b_and_c PROTO ((sbitmap, sbitmap, sbitmap, sbitmap));
extern int sbitmap_a_and_b_or_c PROTO ((sbitmap, sbitmap, sbitmap, sbitmap));
extern int sbitmap_a_and_b PROTO ((sbitmap, sbitmap, sbitmap));
extern int sbitmap_a_or_b PROTO ((sbitmap, sbitmap, sbitmap));
extern void sbitmap_intersect_of_predsucc PROTO ((sbitmap, sbitmap *,
int, int_list_ptr *));
extern void sbitmap_intersect_of_predecessors PROTO ((sbitmap, sbitmap *, int,
int_list_ptr *));
extern void sbitmap_intersect_of_successors PROTO ((sbitmap, sbitmap *, int,
int_list_ptr *));
extern void sbitmap_union_of_predecessors PROTO ((sbitmap, sbitmap *, int,
int_list_ptr *));
...@@ -147,7 +147,7 @@ static int max_uid_for_flow; ...@@ -147,7 +147,7 @@ static int max_uid_for_flow;
This is set up by find_basic_blocks and used there and in life_analysis, This is set up by find_basic_blocks and used there and in life_analysis,
and then freed. */ and then freed. */
static int *uid_block_number; int *uid_block_number;
/* INSN_VOLATILE (insn) is 1 if the insn refers to anything volatile. */ /* INSN_VOLATILE (insn) is 1 if the insn refers to anything volatile. */
...@@ -248,9 +248,9 @@ static rtx last_mem_set; ...@@ -248,9 +248,9 @@ static rtx last_mem_set;
static HARD_REG_SET elim_reg_set; static HARD_REG_SET elim_reg_set;
/* Forward declarations */ /* Forward declarations */
static void find_basic_blocks PROTO((rtx, rtx)); static void find_basic_blocks_1 PROTO((rtx, rtx, int));
static void mark_label_ref PROTO((rtx, rtx, int)); static void mark_label_ref PROTO((rtx, rtx, int));
static void life_analysis PROTO((rtx, int)); static void life_analysis_1 PROTO((rtx, int));
void allocate_for_life_analysis PROTO((void)); void allocate_for_life_analysis PROTO((void));
void init_regset_vector PROTO((regset *, int, struct obstack *)); void init_regset_vector PROTO((regset *, int, struct obstack *));
void free_regset_vector PROTO((regset *, int)); void free_regset_vector PROTO((regset *, int));
...@@ -270,38 +270,31 @@ static int try_pre_increment PROTO((rtx, rtx, HOST_WIDE_INT)); ...@@ -270,38 +270,31 @@ static int try_pre_increment PROTO((rtx, rtx, HOST_WIDE_INT));
#endif #endif
static void mark_used_regs PROTO((regset, regset, rtx, int, rtx)); static void mark_used_regs PROTO((regset, regset, rtx, int, rtx));
void dump_flow_info PROTO((FILE *)); void dump_flow_info PROTO((FILE *));
static void add_pred_succ PROTO ((int, int, int_list_ptr *,
int_list_ptr *, int *, int *));
static int_list_ptr alloc_int_list_node PROTO ((int_list_block **));
static int_list_ptr add_int_list_node PROTO ((int_list_block **,
int_list **, int));
/* Find basic blocks of the current function and perform data flow analysis. /* Find basic blocks of the current function.
F is the first insn of the function and NREGS the number of register numbers F is the first insn of the function and NREGS the number of register numbers
in use. */ in use.
LIVE_REACHABLE_P is non-zero if the caller needs all live blocks to
be reachable. This turns on a kludge that causes the control flow
information to be inaccurate and not suitable for passes like GCSE. */
void void
flow_analysis (f, nregs, file) find_basic_blocks (f, nregs, file, live_reachable_p)
rtx f; rtx f;
int nregs; int nregs;
FILE *file; FILE *file;
int live_reachable_p;
{ {
register rtx insn; register rtx insn;
register int i; register int i;
rtx nonlocal_label_list = nonlocal_label_rtx_list (); rtx nonlocal_label_list = nonlocal_label_rtx_list ();
int in_libcall_block = 0; int in_libcall_block = 0;
#ifdef ELIMINABLE_REGS
static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
#endif
/* Record which registers will be eliminated. We use this in
mark_used_regs. */
CLEAR_HARD_REG_SET (elim_reg_set);
#ifdef ELIMINABLE_REGS
for (i = 0; i < sizeof eliminables / sizeof eliminables[0]; i++)
SET_HARD_REG_BIT (elim_reg_set, eliminables[i].from);
#else
SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM);
#endif
/* Count the basic blocks. Also find maximum insn uid value used. */ /* Count the basic blocks. Also find maximum insn uid value used. */
{ {
...@@ -347,33 +340,27 @@ flow_analysis (f, nregs, file) ...@@ -347,33 +340,27 @@ flow_analysis (f, nregs, file)
} }
} }
n_basic_blocks = i;
#ifdef AUTO_INC_DEC #ifdef AUTO_INC_DEC
/* Leave space for insns we make in some cases for auto-inc. These cases /* Leave space for insns life_analysis makes in some cases for auto-inc.
are rare, so we don't need too much space. */ These cases are rare, so we don't need too much space. */
max_uid_for_flow += max_uid_for_flow / 10; max_uid_for_flow += max_uid_for_flow / 10;
#endif #endif
/* Allocate some tables that last till end of compiling this function /* Allocate some tables that last till end of compiling this function
and some needed only in find_basic_blocks and life_analysis. */ and some needed only in find_basic_blocks and life_analysis. */
n_basic_blocks = i; basic_block_head = (rtx *) xmalloc (n_basic_blocks * sizeof (rtx));
basic_block_head = (rtx *) oballoc (n_basic_blocks * sizeof (rtx)); basic_block_end = (rtx *) xmalloc (n_basic_blocks * sizeof (rtx));
basic_block_end = (rtx *) oballoc (n_basic_blocks * sizeof (rtx)); basic_block_drops_in = (char *) xmalloc (n_basic_blocks);
basic_block_drops_in = (char *) alloca (n_basic_blocks); basic_block_loop_depth = (short *) xmalloc (n_basic_blocks * sizeof (short));
basic_block_loop_depth = (short *) alloca (n_basic_blocks * sizeof (short));
uid_block_number uid_block_number
= (int *) alloca ((max_uid_for_flow + 1) * sizeof (int)); = (int *) xmalloc ((max_uid_for_flow + 1) * sizeof (int));
uid_volatile = (char *) alloca (max_uid_for_flow + 1); uid_volatile = (char *) xmalloc (max_uid_for_flow + 1);
bzero (uid_volatile, max_uid_for_flow + 1); bzero (uid_volatile, max_uid_for_flow + 1);
find_basic_blocks (f, nonlocal_label_list); find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p);
life_analysis (f, nregs);
if (file)
dump_flow_info (file);
basic_block_drops_in = 0;
uid_block_number = 0;
basic_block_loop_depth = 0;
} }
/* Find all basic blocks of the function whose first insn is F. /* Find all basic blocks of the function whose first insn is F.
...@@ -381,11 +368,17 @@ flow_analysis (f, nregs, file) ...@@ -381,11 +368,17 @@ flow_analysis (f, nregs, file)
set up the chains of references for each CODE_LABEL, and set up the chains of references for each CODE_LABEL, and
delete any entire basic blocks that cannot be reached. delete any entire basic blocks that cannot be reached.
NONLOCAL_LABEL_LIST is the same local variable from flow_analysis. */ NONLOCAL_LABEL_LIST is a list of non-local labels in the function.
Blocks that are otherwise unreachable may be reachable with a non-local
goto.
LIVE_REACHABLE_P is non-zero if the caller needs all live blocks to
be reachable. This turns on a kludge that causes the control flow
information to be inaccurate and not suitable for passes like GCSE. */
static void static void
find_basic_blocks (f, nonlocal_label_list) find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
rtx f, nonlocal_label_list; rtx f, nonlocal_label_list;
int live_reachable_p;
{ {
register rtx insn; register rtx insn;
register int i; register int i;
...@@ -685,6 +678,10 @@ find_basic_blocks (f, nonlocal_label_list) ...@@ -685,6 +678,10 @@ find_basic_blocks (f, nonlocal_label_list)
/* Now delete the code for any basic blocks that can't be reached. /* Now delete the code for any basic blocks that can't be reached.
They can occur because jump_optimize does not recognize They can occur because jump_optimize does not recognize
/* Now delete the code for any basic blocks that can't be reached.
They can occur because jump_optimize does not recognize
unreachable loops as unreachable. */ unreachable loops as unreachable. */
deleted = 0; deleted = 0;
...@@ -855,6 +852,24 @@ find_basic_blocks (f, nonlocal_label_list) ...@@ -855,6 +852,24 @@ find_basic_blocks (f, nonlocal_label_list)
} }
} }
/* Record INSN's block number as BB. */
void
set_block_num (insn, bb)
rtx insn;
int bb;
{
if (INSN_UID (insn) >= max_uid_for_flow)
{
/* Add one-eighth the size so we don't keep calling xrealloc. */
max_uid_for_flow = INSN_UID (insn) + (INSN_UID (insn) + 7) / 8;
uid_block_number = (int *)
xrealloc (uid_block_number, (max_uid_for_flow + 1) * sizeof (int));
}
BLOCK_NUM (insn) = bb;
}
/* Subroutines of find_basic_blocks. */ /* Subroutines of find_basic_blocks. */
/* Check expression X for label references; /* Check expression X for label references;
...@@ -932,6 +947,82 @@ flow_delete_insn (insn) ...@@ -932,6 +947,82 @@ flow_delete_insn (insn)
return NEXT_INSN (insn); return NEXT_INSN (insn);
} }
/* Perform data flow analysis.
F is the first insn of the function and NREGS the number of register numbers
in use. */
void
life_analysis (f, nregs, file)
rtx f;
int nregs;
FILE *file;
{
register rtx insn;
register int i;
#ifdef ELIMINABLE_REGS
static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
#endif
/* Record which registers will be eliminated. We use this in
mark_used_regs. */
CLEAR_HARD_REG_SET (elim_reg_set);
#ifdef ELIMINABLE_REGS
for (i = 0; i < sizeof eliminables / sizeof eliminables[0]; i++)
SET_HARD_REG_BIT (elim_reg_set, eliminables[i].from);
#else
SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM);
#endif
life_analysis_1 (f, nregs);
if (file)
dump_flow_info (file);
free_basic_block_vars (1);
}
/* Free the variables allocated by find_basic_blocks.
KEEP_HEAD_END_P is non-zero if basic_block_head and basic_block_end
are not to be freed. */
void
free_basic_block_vars (keep_head_end_p)
int keep_head_end_p;
{
if (basic_block_drops_in)
{
free (basic_block_drops_in);
/* Tell dump_flow_info this isn't available anymore. */
basic_block_drops_in = 0;
}
if (basic_block_loop_depth)
{
free (basic_block_loop_depth);
basic_block_loop_depth = 0;
}
if (uid_block_number)
{
free (uid_block_number);
uid_block_number = 0;
}
if (uid_volatile)
{
free (uid_volatile);
uid_volatile = 0;
}
if (! keep_head_end_p && basic_block_head)
{
free (basic_block_head);
basic_block_head = 0;
free (basic_block_end);
basic_block_end = 0;
}
}
/* Determine which registers are live at the start of each /* Determine which registers are live at the start of each
basic block of the function whose first insn is F. basic block of the function whose first insn is F.
NREGS is the number of registers used in F. NREGS is the number of registers used in F.
...@@ -940,7 +1031,7 @@ flow_delete_insn (insn) ...@@ -940,7 +1031,7 @@ flow_delete_insn (insn)
regset_size and regset_bytes are also set here. */ regset_size and regset_bytes are also set here. */
static void static void
life_analysis (f, nregs) life_analysis_1 (f, nregs)
rtx f; rtx f;
int nregs; int nregs;
{ {
...@@ -3056,3 +3147,718 @@ print_rtl_with_bb (outf, rtx_first) ...@@ -3056,3 +3147,718 @@ print_rtl_with_bb (outf, rtx_first)
} }
} }
} }
/* Integer list support. */
/* Allocate a node from list *HEAD_PTR. */
static int_list_ptr
alloc_int_list_node (head_ptr)
int_list_block **head_ptr;
{
struct int_list_block *first_blk = *head_ptr;
if (first_blk == NULL || first_blk->nodes_left <= 0)
{
first_blk = (struct int_list_block *) xmalloc (sizeof (struct int_list_block));
first_blk->nodes_left = INT_LIST_NODES_IN_BLK;
first_blk->next = *head_ptr;
*head_ptr = first_blk;
}
first_blk->nodes_left--;
return &first_blk->nodes[first_blk->nodes_left];
}
/* Pointer to head of predecessor/successor block list. */
static int_list_block *pred_int_list_blocks;
/* Add a new node to integer list LIST with value VAL.
LIST is a pointer to a list object to allow for different implementations.
If *LIST is initially NULL, the list is empty.
The caller must not care whether the element is added to the front or
to the end of the list (to allow for different implementations). */
static int_list_ptr
add_int_list_node (blk_list, list, val)
int_list_block **blk_list;
int_list **list;
int val;
{
int_list_ptr p = alloc_int_list_node (blk_list);
p->val = val;
p->next = *list;
*list = p;
return p;
}
/* Free the blocks of lists at BLK_LIST. */
void
free_int_list (blk_list)
int_list_block **blk_list;
{
int_list_block *p, *next;
for (p = *blk_list; p != NULL; p = next)
{
next = p->next;
free (p);
}
/* Mark list as empty for the next function we compile. */
*blk_list = NULL;
}
/* Predecessor/successor computation. */
/* Mark PRED_BB a precessor of SUCC_BB,
and conversely SUCC_BB a successor of PRED_BB. */
static void
add_pred_succ (pred_bb, succ_bb, s_preds, s_succs, num_preds, num_succs)
int pred_bb;
int succ_bb;
int_list_ptr *s_preds;
int_list_ptr *s_succs;
int *num_preds;
int *num_succs;
{
if (succ_bb != EXIT_BLOCK)
{
add_int_list_node (&pred_int_list_blocks, &s_preds[succ_bb], pred_bb);
num_preds[succ_bb]++;
}
if (pred_bb != ENTRY_BLOCK)
{
add_int_list_node (&pred_int_list_blocks, &s_succs[pred_bb], succ_bb);
num_succs[pred_bb]++;
}
}
/* Compute the predecessors and successors for each block. */
int
compute_preds_succs (s_preds, s_succs, num_preds, num_succs)
int_list_ptr *s_preds;
int_list_ptr *s_succs;
int *num_preds;
int *num_succs;
{
int bb, clear_local_bb_vars = 0;
bzero ((char *) s_preds, n_basic_blocks * sizeof (int_list_ptr));
bzero ((char *) s_succs, n_basic_blocks * sizeof (int_list_ptr));
bzero ((char *) num_preds, n_basic_blocks * sizeof (int));
bzero ((char *) num_succs, n_basic_blocks * sizeof (int));
/* This routine can be called after life analysis; in that case
basic_block_drops_in and uid_block_number will not be available
and we must recompute their values. */
if (basic_block_drops_in == NULL || uid_block_number == NULL)
{
clear_local_bb_vars = 1;
basic_block_drops_in = (char *) alloca (n_basic_blocks);
uid_block_number = (int *) alloca ((get_max_uid () + 1) * sizeof (int));
bzero ((char *) basic_block_drops_in, n_basic_blocks * sizeof (char));
bzero ((char *) uid_block_number, n_basic_blocks * sizeof (int));
/* Scan each basic block setting basic_block_drops_in and
uid_block_number as needed. */
for (bb = 0; bb < n_basic_blocks; bb++)
{
rtx insn;
for (insn = PREV_INSN (basic_block_head[bb]);
insn && GET_CODE (insn) == NOTE; insn = PREV_INSN (insn))
;
basic_block_drops_in[bb] = insn && GET_CODE (insn) != BARRIER;
insn = basic_block_head[bb];
while (insn)
{
BLOCK_NUM (insn) = bb;
if (insn == basic_block_end[bb])
break;
insn = NEXT_INSN (insn);
}
}
}
for (bb = 0; bb < n_basic_blocks; bb++)
{
rtx head;
rtx jump;
head = BLOCK_HEAD (bb);
if (GET_CODE (head) == CODE_LABEL)
for (jump = LABEL_REFS (head);
jump != head;
jump = LABEL_NEXTREF (jump))
add_pred_succ (BLOCK_NUM (CONTAINING_INSN (jump)), bb,
s_preds, s_succs, num_preds, num_succs);
jump = BLOCK_END (bb);
/* If this is a RETURN insn or a conditional jump in the last
basic block, or a non-jump insn in the last basic block, then
this block reaches the exit block. */
if ((GET_CODE (jump) == JUMP_INSN && GET_CODE (PATTERN (jump)) == RETURN)
|| (((GET_CODE (jump) == JUMP_INSN
&& condjump_p (jump) && !simplejump_p (jump))
|| GET_CODE (jump) != JUMP_INSN)
&& (bb == n_basic_blocks - 1)))
add_pred_succ (bb, EXIT_BLOCK, s_preds, s_succs, num_preds, num_succs);
if (basic_block_drops_in[bb])
add_pred_succ (bb - 1, bb, s_preds, s_succs, num_preds, num_succs);
}
add_pred_succ (ENTRY_BLOCK, 0, s_preds, s_succs, num_preds, num_succs);
/* If we allocated any variables in temporary storage, clear out the
pointer to the local storage to avoid dangling pointers. */
if (clear_local_bb_vars)
{
basic_block_drops_in = NULL;
uid_block_number = NULL;
}
}
void
dump_bb_data (file, preds, succs)
FILE *file;
int_list_ptr *preds;
int_list_ptr *succs;
{
int bb;
int_list_ptr p;
fprintf (file, "BB data\n\n");
for (bb = 0; bb < n_basic_blocks; bb++)
{
fprintf (file, "BB %d, start %d, end %d\n", bb,
INSN_UID (BLOCK_HEAD (bb)), INSN_UID (BLOCK_END (bb)));
fprintf (file, " preds:");
for (p = preds[bb]; p != NULL; p = p->next)
{
int pred_bb = INT_LIST_VAL (p);
if (pred_bb == ENTRY_BLOCK)
fprintf (file, " entry");
else
fprintf (file, " %d", pred_bb);
}
fprintf (file, "\n");
fprintf (file, " succs:");
for (p = succs[bb]; p != NULL; p = p->next)
{
int succ_bb = INT_LIST_VAL (p);
if (succ_bb == EXIT_BLOCK)
fprintf (file, " exit");
else
fprintf (file, " %d", succ_bb);
}
fprintf (file, "\n");
}
fprintf (file, "\n");
}
/* Free basic block data storage. */
void
free_bb_mem ()
{
free_int_list (&pred_int_list_blocks);
}
/* Bitmap manipulation routines. */
/* Allocate a simple bitmap of N_ELMS bits. */
sbitmap
sbitmap_alloc (n_elms)
int n_elms;
{
int bytes, size, amt;
sbitmap bmap;
size = SBITMAP_SET_SIZE (n_elms);
bytes = size * sizeof (SBITMAP_ELT_TYPE);
amt = (sizeof (struct simple_bitmap_def)
+ bytes - sizeof (SBITMAP_ELT_TYPE));
bmap = (sbitmap) xmalloc (amt);
bmap->n_bits = n_elms;
bmap->size = size;
bmap->bytes = bytes;
return bmap;
}
/* Allocate a vector of N_VECS bitmaps of N_ELMS bits. */
sbitmap *
sbitmap_vector_alloc (n_vecs, n_elms)
int n_vecs, n_elms;
{
int i, bytes, offset, elm_bytes, size, amt;
sbitmap *bitmap_vector;
size = SBITMAP_SET_SIZE (n_elms);
bytes = size * sizeof (SBITMAP_ELT_TYPE);
elm_bytes = (sizeof (struct simple_bitmap_def)
+ bytes - sizeof (SBITMAP_ELT_TYPE));
amt = (n_vecs * sizeof (sbitmap *)) + (n_vecs * elm_bytes);
bitmap_vector = (sbitmap *) xmalloc (amt);
/* ??? There may be alignment problems, `offset' should be rounded up
each time to account for alignment. Later [if ever]. */
for (i = 0, offset = n_vecs * sizeof (sbitmap *);
i < n_vecs;
i++, offset += elm_bytes)
{
sbitmap b = (sbitmap) ((char *) bitmap_vector + offset);
bitmap_vector[i] = b;
b->n_bits = n_elms;
b->size = size;
b->bytes = bytes;
}
return bitmap_vector;
}
/* Copy sbitmap SRC to DST. */
void
sbitmap_copy (dst, src)
sbitmap dst, src;
{
int i;
sbitmap_ptr d,s;
s = src->elms;
d = dst->elms;
for (i = 0; i < dst->size; i++)
*d++ = *s++;
}
/* Zero all elements in a bitmap. */
void
sbitmap_zero (bmap)
sbitmap bmap;
{
bzero ((char *) bmap->elms, bmap->bytes);
}
/* Set to ones all elements in a bitmap. */
void
sbitmap_ones (bmap)
sbitmap bmap;
{
memset (bmap->elms, -1, bmap->bytes);
}
/* Zero a vector of N_VECS bitmaps. */
void
sbitmap_vector_zero (bmap, n_vecs)
sbitmap *bmap;
int n_vecs;
{
int i;
for (i = 0; i < n_vecs; i++)
sbitmap_zero (bmap[i]);
}
/* Set to ones a vector of N_VECS bitmaps. */
void
sbitmap_vector_ones (bmap, n_vecs)
sbitmap *bmap;
int n_vecs;
{
int i;
for (i = 0; i < n_vecs; i++)
sbitmap_ones (bmap[i]);
}
/* Set DST to be A union (B - C).
DST = A | (B & ~C).
Return non-zero if any change is made. */
int
sbitmap_union_of_diff (dst, a, b, c)
sbitmap dst, a, b, c;
{
int i,changed;
sbitmap_ptr dstp, ap, bp, cp;
changed = 0;
dstp = dst->elms;
ap = a->elms;
bp = b->elms;
cp = c->elms;
for (i = 0; i < dst->size; i++)
{
SBITMAP_ELT_TYPE tmp = *ap | (*bp & ~*cp);
if (*dstp != tmp)
changed = 1;
*dstp = tmp;
dstp++; ap++; bp++; cp++;
}
return changed;
}
/* Set bitmap DST to the bitwise negation of the bitmap SRC. */
void
sbitmap_not (dst, src)
sbitmap dst, src;
{
int i;
sbitmap_ptr dstp, ap;
dstp = dst->elms;
ap = src->elms;
for (i = 0; i < dst->size; i++)
{
SBITMAP_ELT_TYPE tmp = ~(*ap);
*dstp = tmp;
dstp++; ap++;
}
}
/* Set the bits in DST to be the difference between the bits
in A and the bits in B. i.e. dst = a - b.
The - operator is implemented as a & (~b). */
void
sbitmap_difference (dst, a, b)
sbitmap dst, a, b;
{
int i;
sbitmap_ptr dstp, ap, bp;
dstp = dst->elms;
ap = a->elms;
bp = b->elms;
for (i = 0; i < dst->size; i++)
*dstp++ = *ap++ & (~*bp++);
}
/* Set DST to be (A and B)).
Return non-zero if any change is made. */
int
sbitmap_a_and_b (dst, a, b)
sbitmap dst, a, b;
{
int i,changed;
sbitmap_ptr dstp, ap, bp;
changed = 0;
dstp = dst->elms;
ap = a->elms;
bp = b->elms;
for (i = 0; i < dst->size; i++)
{
SBITMAP_ELT_TYPE tmp = *ap & *bp;
if (*dstp != tmp)
changed = 1;
*dstp = tmp;
dstp++; ap++; bp++;
}
return changed;
}
/* Set DST to be (A or B)).
Return non-zero if any change is made. */
int
sbitmap_a_or_b (dst, a, b)
sbitmap dst, a, b;
{
int i,changed;
sbitmap_ptr dstp, ap, bp;
changed = 0;
dstp = dst->elms;
ap = a->elms;
bp = b->elms;
for (i = 0; i < dst->size; i++)
{
SBITMAP_ELT_TYPE tmp = *ap | *bp;
if (*dstp != tmp)
changed = 1;
*dstp = tmp;
dstp++; ap++; bp++;
}
return changed;
}
/* Set DST to be (A or (B and C)).
Return non-zero if any change is made. */
int
sbitmap_a_or_b_and_c (dst, a, b, c)
sbitmap dst, a, b, c;
{
int i,changed;
sbitmap_ptr dstp, ap, bp, cp;
changed = 0;
dstp = dst->elms;
ap = a->elms;
bp = b->elms;
cp = c->elms;
for (i = 0; i < dst->size; i++)
{
SBITMAP_ELT_TYPE tmp = *ap | (*bp & *cp);
if (*dstp != tmp)
changed = 1;
*dstp = tmp;
dstp++; ap++; bp++; cp++;
}
return changed;
}
/* Set DST to be (A ann (B or C)).
Return non-zero if any change is made. */
int
sbitmap_a_and_b_or_c (dst, a, b, c)
sbitmap dst, a, b, c;
{
int i,changed;
sbitmap_ptr dstp, ap, bp, cp;
changed = 0;
dstp = dst->elms;
ap = a->elms;
bp = b->elms;
cp = c->elms;
for (i = 0; i < dst->size; i++)
{
SBITMAP_ELT_TYPE tmp = *ap & (*bp | *cp);
if (*dstp != tmp)
changed = 1;
*dstp = tmp;
dstp++; ap++; bp++; cp++;
}
return changed;
}
/* Set the bitmap DST to the intersection of SRC of all predecessors or
successors of block number BB (PRED_SUCC says which). */
void
sbitmap_intersect_of_predsucc (dst, src, bb, pred_succ)
sbitmap dst;
sbitmap *src;
int bb;
int_list_ptr *pred_succ;
{
int_list_ptr ps;
int ps_bb;
int set_size = dst->size;
ps = pred_succ[bb];
/* It is possible that there are no predecessors(/successors).
This can happen for example in unreachable code. */
if (ps == NULL)
{
/* In APL-speak this is the `and' reduction of the empty set and thus
the result is the identity for `and'. */
sbitmap_ones (dst);
return;
}
/* Set result to first predecessor/successor. */
for ( ; ps != NULL; ps = ps->next)
{
ps_bb = INT_LIST_VAL (ps);
if (ps_bb == ENTRY_BLOCK || ps_bb == EXIT_BLOCK)
continue;
sbitmap_copy (dst, src[ps_bb]);
/* Break out since we're only doing first predecessor. */
break;
}
if (ps == NULL)
return;
/* Now do the remaining predecessors/successors. */
for (ps = ps->next; ps != NULL; ps = ps->next)
{
int i;
sbitmap_ptr p,r;
ps_bb = INT_LIST_VAL (ps);
if (ps_bb == ENTRY_BLOCK || ps_bb == EXIT_BLOCK)
continue;
p = src[ps_bb]->elms;
r = dst->elms;
for (i = 0; i < set_size; i++)
*r++ &= *p++;
}
}
/* Set the bitmap DST to the intersection of SRC of all predecessors
of block number BB. */
void
sbitmap_intersect_of_predecessors (dst, src, bb, s_preds)
sbitmap dst;
sbitmap *src;
int bb;
int_list_ptr *s_preds;
{
sbitmap_intersect_of_predsucc (dst, src, bb, s_preds);
}
/* Set the bitmap DST to the intersection of SRC of all successors
of block number BB. */
void
sbitmap_intersect_of_successors (dst, src, bb, s_succs)
sbitmap dst;
sbitmap *src;
int bb;
int_list_ptr *s_succs;
{
sbitmap_intersect_of_predsucc (dst, src, bb, s_succs);
}
/* Set the bitmap DST to the union of SRC of all predecessors/successors of
block number BB. */
void
sbitmap_union_of_predsucc (dst, src, bb, pred_succ)
sbitmap dst;
sbitmap *src;
int bb;
int_list_ptr *pred_succ;
{
int_list_ptr ps;
int ps_bb;
int set_size = dst->size;
ps = pred_succ[bb];
/* It is possible that there are no predecessors(/successors).
This can happen for example in unreachable code. */
if (ps == NULL)
{
/* In APL-speak this is the `or' reduction of the empty set and thus
the result is the identity for `or'. */
sbitmap_zero (dst);
return;
}
/* Set result to first predecessor/successor. */
for ( ; ps != NULL; ps = ps->next)
{
ps_bb = INT_LIST_VAL (ps);
if (ps_bb == ENTRY_BLOCK || ps_bb == EXIT_BLOCK)
continue;
sbitmap_copy (dst, src[ps_bb]);
/* Break out since we're only doing first predecessor. */
break;
}
if (ps == NULL)
return;
/* Now do the remaining predecessors/successors. */
for (ps = ps->next; ps != NULL; ps = ps->next)
{
int i;
sbitmap_ptr p,r;
ps_bb = INT_LIST_VAL (ps);
if (ps_bb == ENTRY_BLOCK || ps_bb == EXIT_BLOCK)
continue;
p = src[ps_bb]->elms;
r = dst->elms;
for (i = 0; i < set_size; i++)
*r++ |= *p++;
}
}
/* Set the bitmap DST to the union of SRC of all predecessors of
block number BB. */
void
sbitmap_union_of_predecessors (dst, src, bb, s_preds)
sbitmap dst;
sbitmap *src;
int bb;
int_list_ptr *s_preds;
{
sbitmap_union_of_predsucc (dst, src, bb, s_preds);
}
/* Compute dominator relationships. */
void
compute_dominators (dominators, post_dominators, s_preds, s_succs)
sbitmap *dominators;
sbitmap *post_dominators;
int_list_ptr *s_preds;
int_list_ptr *s_succs;
{
int bb, changed, passes;
sbitmap *temp_bitmap;
temp_bitmap = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
sbitmap_vector_ones (dominators, n_basic_blocks);
sbitmap_vector_ones (post_dominators, n_basic_blocks);
sbitmap_vector_zero (temp_bitmap, n_basic_blocks);
sbitmap_zero (dominators[0]);
SET_BIT (dominators[0], 0);
sbitmap_zero (post_dominators[n_basic_blocks-1]);
SET_BIT (post_dominators[n_basic_blocks-1], 0);
passes = 0;
changed = 1;
while (changed)
{
changed = 0;
for (bb = 1; bb < n_basic_blocks; bb++)
{
sbitmap_intersect_of_predecessors (temp_bitmap[bb], dominators,
bb, s_preds);
SET_BIT (temp_bitmap[bb], bb);
changed |= sbitmap_a_and_b (dominators[bb],
dominators[bb],
temp_bitmap[bb]);
sbitmap_intersect_of_successors (temp_bitmap[bb], post_dominators,
bb, s_succs);
SET_BIT (temp_bitmap[bb], bb);
changed |= sbitmap_a_and_b (post_dominators[bb],
post_dominators[bb],
temp_bitmap[bb]);
}
passes++;
}
free (temp_bitmap);
}
...@@ -521,7 +521,6 @@ static char is_cfg_nonregular PROTO ((void)); ...@@ -521,7 +521,6 @@ static char is_cfg_nonregular PROTO ((void));
static int uses_reg_or_mem PROTO ((rtx)); static int uses_reg_or_mem PROTO ((rtx));
void debug_control_flow PROTO ((void)); void debug_control_flow PROTO ((void));
static void build_control_flow PROTO ((void)); static void build_control_flow PROTO ((void));
static void build_jmp_edges PROTO ((rtx, int));
static void new_edge PROTO ((int, int)); static void new_edge PROTO ((int, int));
...@@ -1310,105 +1309,60 @@ debug_control_flow () ...@@ -1310,105 +1309,60 @@ debug_control_flow ()
} }
/* build the control flow graph. (also set nr_edges accurately) */ /* Build the control flow graph and set nr_edges.
Instead of trying to build a cfg ourselves, we rely on flow to
do it for us. Stamp out useless code (and bug) duplication. */
static void static void
build_control_flow () build_control_flow ()
{ {
int i; int i, j;
int_list_ptr *s_preds;
int_list_ptr *s_succs;
int_list_ptr succ;
int *num_preds;
int *num_succs;
/* The scheduler runs after flow; therefore, we can't blindly call
back into find_basic_blocks since doing so could invalidate the
info in basic_block_live_at_start.
Consider a block consisting entirely of dead stores; after life
analysis it would be a block of NOTE_INSN_DELETED notes. If
we call find_basic_blocks again, then the block would be removed
entirely and invalidate our the register live information.
We could (should?) recompute register live information. Doing
so may even be beneficial. */
s_preds = (int_list_ptr *) alloca (n_basic_blocks * sizeof (int_list_ptr));
s_succs = (int_list_ptr *) alloca (n_basic_blocks * sizeof (int_list_ptr));
num_preds = (int *) alloca (n_basic_blocks * sizeof (int));
num_succs = (int *) alloca (n_basic_blocks * sizeof (int));
compute_preds_succs (s_preds, s_succs, num_preds, num_succs);
nr_edges = 0; nr_edges = 0;
for (i = 0; i < n_basic_blocks; i++) for (i = 0; i < n_basic_blocks; i++)
for (succ = s_succs[i]; succ; succ = succ->next)
{ {
rtx insn; if (INT_LIST_VAL (succ) != EXIT_BLOCK)
new_edge (i, INT_LIST_VAL (succ));
insn = basic_block_end[i];
if (GET_CODE (insn) == JUMP_INSN)
{
build_jmp_edges (PATTERN (insn), i);
}
for (insn = PREV_INSN (basic_block_head[i]);
insn && GET_CODE (insn) == NOTE; insn = PREV_INSN (insn))
;
/* build fallthrough edges */
if (!insn && i != 0)
new_edge (i - 1, i);
else if (insn && GET_CODE (insn) != BARRIER)
new_edge (i - 1, i);
} }
/* increment by 1, since edge 0 is unused. */ /* increment by 1, since edge 0 is unused. */
nr_edges++; nr_edges++;
/* For now. This will move as more and more of haifa is converted
to using the cfg code in flow.c */
free_bb_mem ();
} }
/* construct edges in the control flow graph, from 'source' block, to /* Record an edge in the control flow graph from SOURCE to TARGET.
blocks refered to by 'pattern'. */
static
void
build_jmp_edges (pattern, source)
rtx pattern;
int source;
{
register RTX_CODE code;
register int i;
register char *fmt;
code = GET_CODE (pattern);
if (code == LABEL_REF)
{
register rtx label = XEXP (pattern, 0);
register int target;
/* This can happen as a result of a syntax error
and a diagnostic has already been printed. */
if (INSN_UID (label) == 0)
return;
target = INSN_BLOCK (label);
new_edge (source, target);
return;
}
/* proper handling of ADDR_DIFF_VEC: do not add a non-existing edge
from the block containing the branch-on-table, to itself. */
if (code == ADDR_VEC
|| code == ADDR_DIFF_VEC)
{
int diff_vec_p = GET_CODE (pattern) == ADDR_DIFF_VEC;
int len = XVECLEN (pattern, diff_vec_p);
int k;
for (k = 0; k < len; k++)
{
rtx tem = XVECEXP (pattern, diff_vec_p, k);
build_jmp_edges (tem, source);
}
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
build_jmp_edges (XEXP (pattern, i), source);
if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (pattern, i); j++)
build_jmp_edges (XVECEXP (pattern, i, j), source);
}
}
}
/* construct an edge in the control flow graph, from 'source' to 'target'. */ In theory, this is redundant with the s_succs computed above, but
we have not converted all of haifa to use information from the
integer lists. */
static void static void
new_edge (source, target) new_edge (source, target)
...@@ -8718,8 +8672,6 @@ schedule_insns (dump_file) ...@@ -8718,8 +8672,6 @@ schedule_insns (dump_file)
emit_note_after (NOTE_INSN_DELETED, basic_block_end[n_basic_blocks - 1]); emit_note_after (NOTE_INSN_DELETED, basic_block_end[n_basic_blocks - 1]);
/* Schedule every region in the subroutine */ /* Schedule every region in the subroutine */
fprintf(stderr, "HELLO: nr_regions=%d max_reg_num=%d\n",
(int)nr_regions, (int)max_reg_num());
for (rgn = 0; rgn < nr_regions; rgn++) for (rgn = 0; rgn < nr_regions; rgn++)
{ {
schedule_region (rgn); schedule_region (rgn);
......
...@@ -3381,8 +3381,13 @@ rest_of_compilation (decl) ...@@ -3381,8 +3381,13 @@ rest_of_compilation (decl)
/* Do control and data flow analysis, /* Do control and data flow analysis,
and write some of the results to dump file. */ and write some of the results to dump file. */
TIMEVAR (flow_time, flow_analysis (insns, max_reg_num (), TIMEVAR
rtl_dump_file)); (flow_time,
{
find_basic_blocks (insns, max_reg_num (), rtl_dump_file, 1);
life_analysis (insns, max_reg_num (), rtl_dump_file);
});
if (warn_uninitialized) if (warn_uninitialized)
{ {
uninitialized_vars_warning (DECL_INITIAL (decl)); uninitialized_vars_warning (DECL_INITIAL (decl));
......
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