#include "config.h"
#include "system.h"
#include "rtl.h"
#include "basic-block.h"
#include "insn-config.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "flags.h"
#include "output.h"
#include "except.h"
#include "toplev.h"
#include "recog.h"
#include "insn-flags.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
#ifndef EXIT_IGNORE_STACK
#define EXIT_IGNORE_STACK 0
#endif
extern struct obstack *function_obstack;
extern rtx forced_labels;
int n_basic_blocks;
varray_type basic_block_info;
struct basic_block_def entry_exit_blocks[2] =
{
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
ENTRY_BLOCK,
0
},
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
EXIT_BLOCK,
0
}
};
int flow2_completed;
int max_regno;
varray_type reg_n_info;
unsigned int reg_n_max;
static rtx *reg_next_use;
int regset_bytes;
int regset_size;
regset regs_live_at_setjmp;
rtx regs_may_share;
static int loop_depth;
static int cc0_live;
static rtx mem_set_list;
static HARD_REG_SET elim_reg_set;
varray_type basic_block_for_insn;
static rtx label_value_list;
#define INSN_VOLATILE(INSN) bitmap_bit_p (uid_volatile, INSN_UID (INSN))
#define SET_INSN_VOLATILE(INSN) bitmap_set_bit (uid_volatile, INSN_UID (INSN))
static bitmap uid_volatile;
static int count_basic_blocks PROTO((rtx));
static rtx find_basic_blocks_1 PROTO((rtx, rtx*));
static void create_basic_block PROTO((int, rtx, rtx, rtx));
static void compute_bb_for_insn PROTO((varray_type, int));
static void clear_edges PROTO((void));
static void make_edges PROTO((rtx, rtx*));
static void make_edge PROTO((basic_block, basic_block, int));
static void make_label_edge PROTO((basic_block, rtx, int));
static void mark_critical_edges PROTO((void));
static void commit_one_edge_insertion PROTO((edge));
static void delete_unreachable_blocks PROTO((void));
static void delete_eh_regions PROTO((void));
static int can_delete_note_p PROTO((rtx));
static void delete_insn_chain PROTO((rtx, rtx));
static int delete_block PROTO((basic_block));
static void expunge_block PROTO((basic_block));
static rtx flow_delete_insn PROTO((rtx));
static int can_delete_label_p PROTO((rtx));
static void merge_blocks_nomove PROTO((basic_block, basic_block));
static int merge_blocks PROTO((edge,basic_block,basic_block));
static void tidy_fallthru_edge PROTO((edge,basic_block,basic_block));
static void calculate_loop_depth PROTO((rtx));
static int set_noop_p PROTO((rtx));
static int noop_move_p PROTO((rtx));
static void notice_stack_pointer_modification PROTO ((rtx, rtx));
static void record_volatile_insns PROTO((rtx));
static void mark_regs_live_at_end PROTO((regset));
static void life_analysis_1 PROTO((rtx, int, int));
static void init_regset_vector PROTO ((regset *, int,
struct obstack *));
static void propagate_block PROTO((regset, rtx, rtx, int,
regset, int, int));
static int insn_dead_p PROTO((rtx, regset, int, rtx));
static int libcall_dead_p PROTO((rtx, regset, rtx, rtx));
static void mark_set_regs PROTO((regset, regset, rtx,
rtx, regset));
static void mark_set_1 PROTO((regset, regset, rtx,
rtx, regset));
#ifdef AUTO_INC_DEC
static void find_auto_inc PROTO((regset, rtx, rtx));
static int try_pre_increment_1 PROTO((rtx));
static int try_pre_increment PROTO((rtx, rtx, HOST_WIDE_INT));
#endif
static void mark_used_regs PROTO((regset, regset, rtx, int, rtx));
void dump_flow_info PROTO((FILE *));
static void dump_edge_info PROTO((FILE *, edge, 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));
static void add_pred_succ PROTO ((int, int, int_list_ptr *,
int_list_ptr *, int *, int *));
static void count_reg_sets_1 PROTO ((rtx));
static void count_reg_sets PROTO ((rtx));
static void count_reg_references PROTO ((rtx));
static void notice_stack_pointer_modification PROTO ((rtx, rtx));
static void invalidate_mems_from_autoinc PROTO ((rtx));
void verify_flow_info PROTO ((void));
void
find_basic_blocks (f, nregs, file, do_cleanup)
rtx f;
int nregs ATTRIBUTE_UNUSED;
FILE *file ATTRIBUTE_UNUSED;
int do_cleanup;
{
rtx *bb_eh_end;
int max_uid;
if (basic_block_info != NULL)
{
int i;
clear_edges ();
for (i = 0; i < n_basic_blocks; ++i)
BASIC_BLOCK (i)->aux = NULL;
VARRAY_FREE (basic_block_info);
ENTRY_BLOCK_PTR->aux = NULL;
ENTRY_BLOCK_PTR->global_live_at_end = NULL;
EXIT_BLOCK_PTR->aux = NULL;
EXIT_BLOCK_PTR->global_live_at_start = NULL;
}
n_basic_blocks = count_basic_blocks (f);
VARRAY_BB_INIT (basic_block_info, n_basic_blocks, "basic_block_info");
bb_eh_end = (rtx *) alloca (n_basic_blocks * sizeof (rtx));
label_value_list = find_basic_blocks_1 (f, bb_eh_end);
max_uid = get_max_uid ();
#ifdef AUTO_INC_DEC
max_uid += max_uid / 10;
#endif
VARRAY_BB_INIT (basic_block_for_insn, max_uid, "basic_block_for_insn");
compute_bb_for_insn (basic_block_for_insn, max_uid);
make_edges (label_value_list, bb_eh_end);
if (do_cleanup)
delete_unreachable_blocks ();
mark_critical_edges ();
calculate_loop_depth (f);
label_value_list = 0;
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
}
static int
count_basic_blocks (f)
rtx f;
{
register rtx insn;
register RTX_CODE prev_code;
register int count = 0;
int eh_region = 0;
int call_had_abnormal_edge = 0;
rtx prev_call = NULL_RTX;
prev_code = JUMP_INSN;
for (insn = f; insn; insn = NEXT_INSN (insn))
{
register RTX_CODE code = GET_CODE (insn);
if (code == CODE_LABEL
|| (GET_RTX_CLASS (code) == 'i'
&& (prev_code == JUMP_INSN
|| prev_code == BARRIER
|| (prev_code == CALL_INSN && call_had_abnormal_edge))))
{
count++;
if (count > 0 && prev_call != 0 && !call_had_abnormal_edge)
{
rtx nop = gen_rtx_USE (VOIDmode, const0_rtx);
emit_insn_after (nop, prev_call);
}
}
if (code == CALL_INSN)
{
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
int region = (note ? XINT (XEXP (note, 0), 0) : 1);
prev_call = insn;
call_had_abnormal_edge = 0;
if ((eh_region && region > 0)
|| find_reg_note (insn, REG_EH_RETHROW, NULL_RTX))
call_had_abnormal_edge = 1;
else if (nonlocal_goto_handler_labels && region >= 0)
call_had_abnormal_edge = 1;
}
else if (code != NOTE)
prev_call = NULL_RTX;
if (code != NOTE)
prev_code = code;
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
++eh_region;
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
--eh_region;
}
if (count == 0)
{
emit_insn (gen_rtx_USE (VOIDmode, const0_rtx));
count = 1;
}
return count;
}
static rtx
find_basic_blocks_1 (f, bb_eh_end)
rtx f;
rtx *bb_eh_end;
{
register rtx insn, next;
int call_has_abnormal_edge = 0;
int i = 0;
rtx bb_note = NULL_RTX;
rtx eh_list = NULL_RTX;
rtx label_value_list = NULL_RTX;
rtx head = NULL_RTX;
rtx end = NULL_RTX;
for (insn = f; insn; insn = next)
{
enum rtx_code code = GET_CODE (insn);
next = NEXT_INSN (insn);
if (code == CALL_INSN)
{
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
int region = (note ? XINT (XEXP (note, 0), 0) : 1);
call_has_abnormal_edge = 0;
if ((eh_list && region > 0)
|| find_reg_note (insn, REG_EH_RETHROW, NULL_RTX))
call_has_abnormal_edge = 1;
else
{
if (nonlocal_goto_handler_labels && region >= 0)
call_has_abnormal_edge = 1;
}
}
switch (code)
{
case NOTE:
{
int kind = NOTE_LINE_NUMBER (insn);
if (kind == NOTE_INSN_EH_REGION_BEG)
eh_list = gen_rtx_INSN_LIST (VOIDmode, insn, eh_list);
else if (kind == NOTE_INSN_EH_REGION_END)
eh_list = XEXP (eh_list, 1);
else if (kind == NOTE_INSN_BASIC_BLOCK)
{
if (bb_note == NULL_RTX)
bb_note = insn;
else
next = flow_delete_insn (insn);
}
break;
}
case CODE_LABEL:
if (head != NULL_RTX)
{
if (GET_CODE (end) == CALL_INSN)
{
rtx nop = gen_rtx_USE (VOIDmode, const0_rtx);
end = emit_insn_after (nop, end);
}
bb_eh_end[i] = eh_list;
create_basic_block (i++, head, end, bb_note);
bb_note = NULL_RTX;
}
head = end = insn;
break;
case JUMP_INSN:
if (head == NULL_RTX)
head = insn;
else
{
if (GET_CODE (PATTERN (insn)) == ADDR_VEC
|| GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
{
head = end = NULL;
n_basic_blocks--;
break;
}
}
end = insn;
goto new_bb_inclusive;
case BARRIER:
if (head == NULL_RTX)
break;
if (GET_CODE (end) == CALL_INSN)
{
rtx nop = gen_rtx_USE (VOIDmode, const0_rtx);
end = emit_insn_after (nop, end);
}
goto new_bb_exclusive;
case CALL_INSN:
if (call_has_abnormal_edge)
{
new_bb_inclusive:
if (head == NULL_RTX)
head = insn;
end = insn;
new_bb_exclusive:
bb_eh_end[i] = eh_list;
create_basic_block (i++, head, end, bb_note);
head = end = NULL_RTX;
bb_note = NULL_RTX;
break;
}
default:
if (GET_RTX_CLASS (code) == 'i')
{
if (head == NULL_RTX)
head = insn;
end = insn;
}
break;
}
if (GET_RTX_CLASS (code) == 'i')
{
rtx note;
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_LABEL)
{
rtx lab = XEXP (note, 0), next;
if (lab == eh_return_stub_label)
;
else if ((next = next_nonnote_insn (lab)) != NULL
&& GET_CODE (next) == JUMP_INSN
&& (GET_CODE (PATTERN (next)) == ADDR_VEC
|| GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
;
else
label_value_list
= gen_rtx_EXPR_LIST (VOIDmode, XEXP (note, 0),
label_value_list);
}
}
}
if (head != NULL_RTX)
{
bb_eh_end[i] = eh_list;
create_basic_block (i++, head, end, bb_note);
}
if (i != n_basic_blocks)
abort ();
return label_value_list;
}
static void
create_basic_block (index, head, end, bb_note)
int index;
rtx head, end, bb_note;
{
basic_block bb;
if (bb_note
&& ! RTX_INTEGRATED_P (bb_note)
&& (bb = NOTE_BASIC_BLOCK (bb_note)) != NULL
&& bb->aux == NULL)
{
rtx after;
if (GET_CODE (head) == CODE_LABEL)
after = head;
else
{
after = PREV_INSN (head);
head = bb_note;
}
if (after != bb_note && NEXT_INSN (after) != bb_note)
reorder_insns (bb_note, bb_note, after);
}
else
{
bb = (basic_block) obstack_alloc (function_obstack, sizeof (*bb));
memset (bb, 0, sizeof (*bb));
if (GET_CODE (head) == CODE_LABEL)
bb_note = emit_note_after (NOTE_INSN_BASIC_BLOCK, head);
else
{
bb_note = emit_note_before (NOTE_INSN_BASIC_BLOCK, head);
head = bb_note;
}
NOTE_BASIC_BLOCK (bb_note) = bb;
}
if (NEXT_INSN (end) == bb_note)
end = bb_note;
bb->head = head;
bb->end = end;
bb->index = index;
BASIC_BLOCK (index) = bb;
bb->aux = bb;
}
static void
compute_bb_for_insn (bb_for_insn, max)
varray_type bb_for_insn;
int max;
{
int i;
for (i = 0; i < n_basic_blocks; ++i)
{
basic_block bb = BASIC_BLOCK (i);
rtx insn, end;
end = bb->end;
insn = bb->head;
while (1)
{
int uid = INSN_UID (insn);
if (uid < max)
VARRAY_BB (bb_for_insn, uid) = bb;
if (insn == end)
break;
insn = NEXT_INSN (insn);
}
}
}
static void
clear_edges ()
{
int i;
edge n, e;
for (i = 0; i < n_basic_blocks; ++i)
{
basic_block bb = BASIC_BLOCK (i);
for (e = bb->succ; e ; e = n)
{
n = e->succ_next;
free (e);
}
bb->succ = 0;
bb->pred = 0;
}
for (e = ENTRY_BLOCK_PTR->succ; e ; e = n)
{
n = e->succ_next;
free (e);
}
ENTRY_BLOCK_PTR->succ = 0;
EXIT_BLOCK_PTR->pred = 0;
}
static void
make_edges (label_value_list, bb_eh_end)
rtx label_value_list;
rtx *bb_eh_end;
{
int i;
current_function_has_computed_jump = 0;
make_edge (ENTRY_BLOCK_PTR, BASIC_BLOCK (0), EDGE_FALLTHRU);
for (i = 0; i < n_basic_blocks; ++i)
{
basic_block bb = BASIC_BLOCK (i);
rtx insn, x, eh_list;
enum rtx_code code;
int force_fallthru = 0;
eh_list = bb_eh_end[i];
if (asynchronous_exceptions)
{
for (insn = bb->end; insn != bb->head; insn = PREV_INSN (insn))
{
if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
eh_list = gen_rtx_INSN_LIST (VOIDmode, insn, eh_list);
}
}
insn = bb->end;
code = GET_CODE (insn);
if (code == JUMP_INSN)
{
rtx tmp;
if ((tmp = JUMP_LABEL (insn)) != NULL_RTX
&& (tmp = NEXT_INSN (tmp)) != NULL_RTX
&& GET_CODE (tmp) == JUMP_INSN
&& (GET_CODE (PATTERN (tmp)) == ADDR_VEC
|| GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC))
{
rtvec vec;
int j;
if (GET_CODE (PATTERN (tmp)) == ADDR_VEC)
vec = XVEC (PATTERN (tmp), 0);
else
vec = XVEC (PATTERN (tmp), 1);
for (j = GET_NUM_ELEM (vec) - 1; j >= 0; --j)
make_label_edge (bb, XEXP (RTVEC_ELT (vec, j), 0), 0);
if ((tmp = single_set (insn)) != NULL
&& SET_DEST (tmp) == pc_rtx
&& GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE
&& GET_CODE (XEXP (SET_SRC (tmp), 2)) == LABEL_REF)
make_label_edge (bb, XEXP (XEXP (SET_SRC (tmp), 2), 0), 0);
#ifdef CASE_DROPS_THROUGH
force_fallthru = 1;
#endif
}
else if (computed_jump_p (insn))
{
current_function_has_computed_jump = 1;
for (x = label_value_list; x; x = XEXP (x, 1))
make_label_edge (bb, XEXP (x, 0), EDGE_ABNORMAL);
for (x = forced_labels; x; x = XEXP (x, 1))
make_label_edge (bb, XEXP (x, 0), EDGE_ABNORMAL);
}
else if (returnjump_p (insn))
make_edge (bb, EXIT_BLOCK_PTR, 0);
else
{
if (! JUMP_LABEL (insn))
abort ();
make_label_edge (bb, JUMP_LABEL (insn), 0);
}
}
if (code == CALL_INSN || asynchronous_exceptions)
{
int is_call = (code == CALL_INSN ? EDGE_ABNORMAL_CALL : 0);
handler_info *ptr;
x = find_reg_note (insn, REG_EH_RETHROW, 0);
if (!x)
x = find_reg_note (insn, REG_EH_REGION, 0);
if (x)
{
if (XINT (XEXP (x, 0), 0) > 0)
{
ptr = get_first_handler (XINT (XEXP (x, 0), 0));
while (ptr)
{
make_label_edge (bb, ptr->handler_label,
EDGE_ABNORMAL | EDGE_EH | is_call);
ptr = ptr->next;
}
}
}
else
{
for (x = eh_list; x; x = XEXP (x, 1))
{
ptr = get_first_handler (NOTE_BLOCK_NUMBER (XEXP (x, 0)));
while (ptr)
{
make_label_edge (bb, ptr->handler_label,
EDGE_ABNORMAL | EDGE_EH | is_call);
ptr = ptr->next;
}
}
}
if (code == CALL_INSN && nonlocal_goto_handler_labels)
{
for (x = nonlocal_goto_handler_labels; x ; x = XEXP (x, 1))
make_label_edge (bb, XEXP (x, 0),
EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
}
}
if (i + 1 == n_basic_blocks && eh_return_stub_label != 0)
make_label_edge (bb, eh_return_stub_label, EDGE_EH);
insn = next_nonnote_insn (insn);
if (!insn || (i + 1 == n_basic_blocks && force_fallthru))
make_edge (bb, EXIT_BLOCK_PTR, EDGE_FALLTHRU);
else if (i + 1 < n_basic_blocks)
{
rtx tmp = BLOCK_HEAD (i + 1);
if (GET_CODE (tmp) == NOTE)
tmp = next_nonnote_insn (tmp);
if (force_fallthru || insn == tmp)
make_edge (bb, BASIC_BLOCK (i + 1), EDGE_FALLTHRU);
}
}
}
static void
make_edge (src, dst, flags)
basic_block src, dst;
int flags;
{
edge e;
for (e = src->succ; e ; e = e->succ_next)
if (e->dest == dst)
{
e->flags |= flags;
return;
}
e = (edge) xcalloc (1, sizeof (*e));
e->succ_next = src->succ;
e->pred_next = dst->pred;
e->src = src;
e->dest = dst;
e->flags = flags;
src->succ = e;
dst->pred = e;
}
static void
make_label_edge (src, label, flags)
basic_block src;
rtx label;
int flags;
{
if (GET_CODE (label) != CODE_LABEL)
abort ();
if (INSN_UID (label) == 0)
return;
make_edge (src, BLOCK_FOR_INSN (label), flags);
}
static void
mark_critical_edges ()
{
int i, n = n_basic_blocks;
basic_block bb;
bb = ENTRY_BLOCK_PTR;
i = -1;
while (1)
{
edge e;
if (bb->succ && bb->succ->succ_next)
{
for (e = bb->succ; e ; e = e->succ_next)
{
if (e->dest->pred->pred_next)
e->flags |= EDGE_CRITICAL;
else
e->flags &= ~EDGE_CRITICAL;
}
}
else
{
for (e = bb->succ; e ; e = e->succ_next)
e->flags &= ~EDGE_CRITICAL;
}
if (++i >= n)
break;
bb = BASIC_BLOCK (i);
}
}
basic_block
split_edge (edge_in)
edge edge_in;
{
basic_block old_pred, bb, old_succ;
edge edge_out;
rtx bb_note;
int i, j;
if ((edge_in->flags & EDGE_ABNORMAL) != 0)
abort ();
old_pred = edge_in->src;
old_succ = edge_in->dest;
{
edge *pp;
for (pp = &old_succ->pred; *pp != edge_in; pp = &(*pp)->pred_next)
continue;
*pp = edge_in->pred_next;
edge_in->pred_next = NULL;
}
bb = (basic_block) obstack_alloc (function_obstack, sizeof (*bb));
edge_out = (edge) xcalloc (1, sizeof (*edge_out));
memset (bb, 0, sizeof (*bb));
bb->local_set = OBSTACK_ALLOC_REG_SET (function_obstack);
bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (function_obstack);
bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (function_obstack);
CLEAR_REG_SET (bb->local_set);
if (old_succ->global_live_at_start)
{
COPY_REG_SET (bb->global_live_at_start, old_succ->global_live_at_start);
COPY_REG_SET (bb->global_live_at_end, old_succ->global_live_at_start);
}
else
{
CLEAR_REG_SET (bb->global_live_at_start);
CLEAR_REG_SET (bb->global_live_at_end);
}
bb->pred = edge_in;
bb->succ = edge_out;
edge_in->dest = bb;
edge_in->flags &= ~EDGE_CRITICAL;
edge_out->pred_next = old_succ->pred;
edge_out->succ_next = NULL;
edge_out->src = bb;
edge_out->dest = old_succ;
edge_out->flags = EDGE_FALLTHRU;
edge_out->probability = REG_BR_PROB_BASE;
old_succ->pred = edge_out;
if ((edge_in->flags & EDGE_FALLTHRU) == 0)
{
edge e;
for (e = edge_out->pred_next; e ; e = e->pred_next)
if (e->flags & EDGE_FALLTHRU)
break;
if (e)
{
basic_block jump_block;
rtx pos;
if ((e->flags & EDGE_CRITICAL) == 0
&& e->src != ENTRY_BLOCK_PTR)
{
jump_block = e->src;
}
else
{
jump_block = split_edge (e);
e = jump_block->succ;
}
pos = emit_jump_insn_after (gen_jump (old_succ->head),
jump_block->end);
jump_block->end = pos;
if (basic_block_for_insn)
set_block_for_insn (pos, jump_block);
emit_barrier_after (pos);
JUMP_LABEL (pos) = old_succ->head;
++LABEL_NUSES (old_succ->head);
e->flags &= ~EDGE_FALLTHRU;
}
}
VARRAY_GROW (basic_block_info, ++n_basic_blocks);
if (old_succ == EXIT_BLOCK_PTR)
j = n_basic_blocks - 1;
else
j = old_succ->index;
for (i = n_basic_blocks - 1; i > j; --i)
{
basic_block tmp = BASIC_BLOCK (i - 1);
BASIC_BLOCK (i) = tmp;
tmp->index = i;
}
BASIC_BLOCK (i) = bb;
bb->index = i;
if (old_succ != EXIT_BLOCK_PTR
&& PREV_INSN (old_succ->head)
&& GET_CODE (PREV_INSN (old_succ->head)) == NOTE
&& NOTE_LINE_NUMBER (PREV_INSN (old_succ->head)) == NOTE_INSN_LOOP_BEG)
bb_note = emit_note_before (NOTE_INSN_BASIC_BLOCK,
PREV_INSN (old_succ->head));
else if (old_succ != EXIT_BLOCK_PTR)
bb_note = emit_note_before (NOTE_INSN_BASIC_BLOCK, old_succ->head);
else
bb_note = emit_note_after (NOTE_INSN_BASIC_BLOCK, get_last_insn ());
NOTE_BASIC_BLOCK (bb_note) = bb;
bb->head = bb->end = bb_note;
if ((edge_in->flags & EDGE_FALLTHRU) == 0)
{
rtx tmp, insn = old_pred->end;
rtx old_label = old_succ->head;
rtx new_label = gen_label_rtx ();
if (GET_CODE (insn) != JUMP_INSN)
abort ();
if ((tmp = JUMP_LABEL (insn)) != NULL_RTX
&& (tmp = NEXT_INSN (tmp)) != NULL_RTX
&& GET_CODE (tmp) == JUMP_INSN
&& (GET_CODE (PATTERN (tmp)) == ADDR_VEC
|| GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC))
{
rtvec vec;
int j;
if (GET_CODE (PATTERN (tmp)) == ADDR_VEC)
vec = XVEC (PATTERN (tmp), 0);
else
vec = XVEC (PATTERN (tmp), 1);
for (j = GET_NUM_ELEM (vec) - 1; j >= 0; --j)
if (XEXP (RTVEC_ELT (vec, j), 0) == old_label)
{
RTVEC_ELT (vec, j) = gen_rtx_LABEL_REF (VOIDmode, new_label);
--LABEL_NUSES (old_label);
++LABEL_NUSES (new_label);
}
if ((tmp = single_set (insn)) != NULL
&& SET_DEST (tmp) == pc_rtx
&& GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE
&& GET_CODE (XEXP (SET_SRC (tmp), 2)) == LABEL_REF
&& XEXP (XEXP (SET_SRC (tmp), 2), 0) == old_label)
{
XEXP (SET_SRC (tmp), 2) = gen_rtx_LABEL_REF (VOIDmode,
new_label);
--LABEL_NUSES (old_label);
++LABEL_NUSES (new_label);
}
}
else
{
if (computed_jump_p (insn))
abort ();
if (returnjump_p (insn))
abort ();
if (JUMP_LABEL (insn) != old_label)
abort ();
redirect_jump (insn, new_label);
}
emit_label_before (new_label, bb_note);
bb->head = new_label;
}
return bb;
}
void
insert_insn_on_edge (pattern, e)
rtx pattern;
edge e;
{
if ((e->flags & (EDGE_ABNORMAL|EDGE_CRITICAL))
== (EDGE_ABNORMAL|EDGE_CRITICAL))
abort ();
if (e->insns == NULL_RTX)
start_sequence ();
else
push_to_sequence (e->insns);
emit_insn (pattern);
e->insns = get_insns ();
end_sequence();
}
static void
commit_one_edge_insertion (e)
edge e;
{
rtx before = NULL_RTX, after = NULL_RTX, tmp;
basic_block bb;
if (e->dest->pred->pred_next == NULL
&& e->dest != EXIT_BLOCK_PTR)
{
bb = e->dest;
tmp = bb->head;
if (GET_CODE (tmp) == CODE_LABEL)
tmp = NEXT_INSN (tmp);
if (GET_CODE (tmp) == NOTE
&& NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BASIC_BLOCK)
tmp = NEXT_INSN (tmp);
if (tmp == bb->head)
before = tmp;
else
after = PREV_INSN (tmp);
}
else if ((e->flags & EDGE_ABNORMAL) == 0
&& e->src->succ->succ_next == NULL
&& e->src != ENTRY_BLOCK_PTR)
{
bb = e->src;
if (GET_CODE (bb->end) == JUMP_INSN)
{
if (! simplejump_p (bb->end))
abort ();
before = bb->end;
}
else
{
if ((e->flags & EDGE_FALLTHRU) == 0)
abort ();
after = bb->end;
}
}
else
{
bb = split_edge (e);
after = bb->end;
}
tmp = e->insns;
e->insns = NULL_RTX;
if (basic_block_for_insn)
{
rtx i;
for (i = tmp; i != NULL_RTX; i = NEXT_INSN (i))
set_block_for_insn (i, bb);
}
if (before)
{
emit_insns_before (tmp, before);
if (before == bb->head)
bb->head = tmp;
}
else
{
tmp = emit_insns_after (tmp, after);
if (after == bb->end)
bb->end = tmp;
}
}
void
commit_edge_insertions ()
{
int i;
basic_block bb;
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
i = -1;
bb = ENTRY_BLOCK_PTR;
while (1)
{
edge e, next;
for (e = bb->succ; e ; e = next)
{
next = e->succ_next;
if (e->insns)
commit_one_edge_insertion (e);
}
if (++i >= n_basic_blocks)
break;
bb = BASIC_BLOCK (i);
}
}
static void
delete_unreachable_blocks ()
{
basic_block *worklist, *tos;
int deleted_handler;
edge e;
int i, n;
n = n_basic_blocks;
tos = worklist = (basic_block *) alloca (sizeof (basic_block) * n);
for (i = 0; i < n; ++i)
BASIC_BLOCK (i)->aux = NULL;
for (e = ENTRY_BLOCK_PTR->succ; e ; e = e->succ_next)
{
*tos++ = e->dest;
e->dest->aux = e;
}
while (tos != worklist)
{
basic_block b = *--tos;
for (e = b->succ; e ; e = e->succ_next)
if (!e->dest->aux)
{
*tos++ = e->dest;
e->dest->aux = e;
}
}
deleted_handler = 0;
for (i = n - 1; i >= 0; --i)
{
basic_block b = BASIC_BLOCK (i);
if (b->aux != NULL)
b->aux = NULL;
else
deleted_handler |= delete_block (b);
}
for (i = 1; i < n_basic_blocks; ++i)
{
basic_block b = BASIC_BLOCK (i - 1);
basic_block c = BASIC_BLOCK (i);
edge s;
if ((s = b->succ) != NULL
&& s->succ_next == NULL
&& s->dest == c
&& GET_CODE (b->end) == JUMP_INSN
&& condjump_p (b->end))
tidy_fallthru_edge (s, b, c);
}
for (i = 0; i < n_basic_blocks; )
{
basic_block c, b = BASIC_BLOCK (i);
edge s;
while ((s = b->succ) != NULL
&& s->succ_next == NULL
&& (s->flags & EDGE_EH) == 0
&& (c = s->dest) != EXIT_BLOCK_PTR
&& c->pred->pred_next == NULL
&& GET_CODE (b->end) == JUMP_INSN
&& condjump_p (b->end)
&& merge_blocks (s, b, c))
continue;
i = b->index + 1;
}
if (deleted_handler)
delete_eh_regions ();
}
static void
delete_eh_regions ()
{
rtx insn;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE)
{
if ((NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG) ||
(NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
{
int num = CODE_LABEL_NUMBER (insn);
if (get_first_handler (num) == NULL && ! rethrow_used (num))
{
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
}
}
}
}
static int
can_delete_note_p (note)
rtx note;
{
return (NOTE_LINE_NUMBER (note) == NOTE_INSN_DELETED
|| NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK);
}
static void
delete_insn_chain (start, finish)
rtx start, finish;
{
rtx next;
while (1)
{
next = NEXT_INSN (start);
if (GET_CODE (start) == NOTE && !can_delete_note_p (start))
;
else if (GET_CODE (start) == CODE_LABEL && !can_delete_label_p (start))
;
else
next = flow_delete_insn (start);
if (start == finish)
break;
start = next;
}
}
static int
delete_block (b)
basic_block b;
{
int deleted_handler = 0;
rtx insn, end;
insn = b->head;
if (GET_CODE (insn) == CODE_LABEL)
{
rtx x, *prev = &exception_handler_labels;
for (x = exception_handler_labels; x; x = XEXP (x, 1))
{
if (XEXP (x, 0) == insn)
{
*prev = XEXP (x, 1);
XEXP (x, 1) = NULL_RTX;
XEXP (x, 0) = NULL_RTX;
remove_handler (insn);
deleted_handler = 1;
break;
}
prev = &XEXP (x, 1);
}
if (!can_delete_label_p (insn))
{
if (insn == b->end)
goto no_delete_insns;
insn = NEXT_INSN (insn);
}
}
end = next_nonnote_insn (b->end);
if (!end || GET_CODE (end) != BARRIER)
end = b->end;
delete_insn_chain (insn, end);
no_delete_insns:
{
edge e, next, *q;
for (e = b->pred; e ; e = next)
{
for (q = &e->src->succ; *q != e; q = &(*q)->succ_next)
continue;
*q = e->succ_next;
next = e->pred_next;
free (e);
}
for (e = b->succ; e ; e = next)
{
for (q = &e->dest->pred; *q != e; q = &(*q)->pred_next)
continue;
*q = e->pred_next;
next = e->succ_next;
free (e);
}
b->pred = NULL;
b->succ = NULL;
}
expunge_block (b);
return deleted_handler;
}
static void
expunge_block (b)
basic_block b;
{
int i, n = n_basic_blocks;
for (i = b->index; i + 1 < n; ++i)
{
basic_block x = BASIC_BLOCK (i + 1);
BASIC_BLOCK (i) = x;
x->index = i;
}
basic_block_info->num_elements--;
n_basic_blocks--;
}
static rtx
flow_delete_insn (insn)
rtx insn;
{
rtx prev = PREV_INSN (insn);
rtx next = NEXT_INSN (insn);
rtx note;
PREV_INSN (insn) = NULL_RTX;
NEXT_INSN (insn) = NULL_RTX;
INSN_DELETED_P (insn) = 1;
if (prev)
NEXT_INSN (prev) = next;
if (next)
PREV_INSN (next) = prev;
else
set_last_insn (prev);
if (GET_CODE (insn) == CODE_LABEL)
remove_node_from_expr_list (insn, &nonlocal_goto_handler_labels);
if (GET_CODE (insn) == JUMP_INSN
&& JUMP_LABEL (insn)
&& GET_CODE (JUMP_LABEL (insn)) == CODE_LABEL)
LABEL_NUSES (JUMP_LABEL (insn))--;
else if ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != NULL_RTX
&& GET_CODE (XEXP (note, 0)) == CODE_LABEL)
LABEL_NUSES (XEXP (note, 0))--;
return next;
}
static int
can_delete_label_p (label)
rtx label;
{
rtx x;
if (LABEL_PRESERVE_P (label))
return 0;
for (x = forced_labels; x ; x = XEXP (x, 1))
if (label == XEXP (x, 0))
return 0;
for (x = label_value_list; x ; x = XEXP (x, 1))
if (label == XEXP (x, 0))
return 0;
for (x = exception_handler_labels; x ; x = XEXP (x, 1))
if (label == XEXP (x, 0))
return 0;
if (LABEL_NAME (label) != 0)
return 0;
return 1;
}
static void
merge_blocks_nomove (a, b)
basic_block a, b;
{
edge e;
rtx b_head, b_end, a_end;
int b_empty = 0;
b_head = b->head;
b_end = b->end;
if (GET_CODE (b_head) == CODE_LABEL)
{
if (b_head == b_end)
b_empty = 1;
b_head = flow_delete_insn (b_head);
}
if (GET_CODE (b_head) == NOTE
&& NOTE_LINE_NUMBER (b_head) == NOTE_INSN_BASIC_BLOCK)
{
if (b_head == b_end)
b_empty = 1;
b_head = flow_delete_insn (b_head);
}
a_end = a->end;
if (GET_CODE (a_end) == JUMP_INSN)
{
rtx prev;
prev = prev_nonnote_insn (a_end);
if (!prev)
prev = a->head;
#ifdef HAVE_cc0
if (prev && sets_cc0_p (prev))
{
rtx tmp = prev;
prev = prev_nonnote_insn (prev);
if (!prev)
prev = a->head;
flow_delete_insn (tmp);
}
#endif
flow_delete_insn (a_end);
a_end = prev;
}
free (a->succ);
for (e = b->succ; e ; e = e->succ_next)
e->src = a;
a->succ = b->succ;
if (!b_empty)
{
BLOCK_FOR_INSN (b_head) = a;
while (b_head != b_end)
{
b_head = NEXT_INSN (b_head);
BLOCK_FOR_INSN (b_head) = a;
}
a_end = b_head;
}
a->end = a_end;
expunge_block (b);
}
static int
merge_blocks (e, b, c)
edge e;
basic_block b, c;
{
if (!(e->flags & EDGE_FALLTHRU))
{
return 0;
}
{
rtx insn, stop = NEXT_INSN (c->head);
for (insn = NEXT_INSN (b->end); insn != stop; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == CODE_LABEL && !can_delete_label_p (insn))
return 0;
}
merge_blocks_nomove (b, c);
return 1;
}
static void
tidy_fallthru_edge (e, b, c)
edge e;
basic_block b, c;
{
rtx q;
if (next_real_insn (b->end) != next_real_insn (PREV_INSN (c->head)))
return;
q = b->end;
if (GET_CODE (q) == JUMP_INSN)
{
#ifdef HAVE_cc0
if (! simplejump_p (q) && condjump_p (q))
q = PREV_INSN (q);
#endif
if (b->head == q)
{
PUT_CODE (q, NOTE);
NOTE_LINE_NUMBER (q) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (q) = 0;
}
else
b->end = q = PREV_INSN (q);
}
if (q != PREV_INSN (c->head))
delete_insn_chain (NEXT_INSN (q), PREV_INSN (c->head));
e->flags |= EDGE_FALLTHRU;
}
static void
calculate_loop_depth (insns)
rtx insns;
{
basic_block bb;
rtx insn;
int i = 0, depth = 1;
bb = BASIC_BLOCK (i);
for (insn = insns; insn ; insn = NEXT_INSN (insn))
{
if (insn == bb->head)
{
bb->loop_depth = depth;
if (++i >= n_basic_blocks)
break;
bb = BASIC_BLOCK (i);
}
if (GET_CODE (insn) == NOTE)
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
depth++;
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
depth--;
if (depth == 0)
abort ();
}
}
}
void
life_analysis (f, nregs, file, remove_dead_code)
rtx f;
int nregs;
FILE *file;
int remove_dead_code;
{
#ifdef ELIMINABLE_REGS
register size_t i;
static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
#endif
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
uid_volatile = BITMAP_ALLOCA ();
init_alias_analysis ();
life_analysis_1 (f, nregs, remove_dead_code);
end_alias_analysis ();
if (file)
dump_flow_info (file);
BITMAP_FREE (uid_volatile);
free_basic_block_vars (1);
}
void
free_basic_block_vars (keep_head_end_p)
int keep_head_end_p;
{
if (basic_block_for_insn)
{
VARRAY_FREE (basic_block_for_insn);
basic_block_for_insn = NULL;
}
if (! keep_head_end_p)
{
clear_edges ();
VARRAY_FREE (basic_block_info);
n_basic_blocks = 0;
ENTRY_BLOCK_PTR->aux = NULL;
ENTRY_BLOCK_PTR->global_live_at_end = NULL;
EXIT_BLOCK_PTR->aux = NULL;
EXIT_BLOCK_PTR->global_live_at_start = NULL;
}
}
static int
set_noop_p (set)
rtx set;
{
rtx src = SET_SRC (set);
rtx dst = SET_DEST (set);
if (GET_CODE (src) == SUBREG && GET_CODE (dst) == SUBREG)
{
if (SUBREG_WORD (src) != SUBREG_WORD (dst))
return 0;
src = SUBREG_REG (src);
dst = SUBREG_REG (dst);
}
return (GET_CODE (src) == REG && GET_CODE (dst) == REG
&& REGNO (src) == REGNO (dst));
}
static int
noop_move_p (insn)
rtx insn;
{
rtx pat = PATTERN (insn);
if (find_reg_note (insn, REG_EQUAL, NULL_RTX))
return 0;
if (GET_CODE (pat) == SET && set_noop_p (pat))
return 1;
if (GET_CODE (pat) == PARALLEL)
{
int i;
for (i = 0; i < XVECLEN (pat, 0); i++)
{
rtx tem = XVECEXP (pat, 0, i);
if (GET_CODE (tem) == USE
|| GET_CODE (tem) == CLOBBER)
continue;
if (GET_CODE (tem) != SET || ! set_noop_p (tem))
return 0;
}
return 1;
}
return 0;
}
static void
notice_stack_pointer_modification (x, pat)
rtx x;
rtx pat ATTRIBUTE_UNUSED;
{
if (x == stack_pointer_rtx
|| (GET_CODE (x) == MEM
&& (GET_CODE (XEXP (x, 0)) == PRE_DEC
|| GET_CODE (XEXP (x, 0)) == PRE_INC
|| GET_CODE (XEXP (x, 0)) == POST_DEC
|| GET_CODE (XEXP (x, 0)) == POST_INC)
&& XEXP (XEXP (x, 0), 0) == stack_pointer_rtx))
current_function_sp_is_unchanging = 0;
}
static void
record_volatile_insns (f)
rtx f;
{
rtx insn;
for (insn = f; insn; insn = NEXT_INSN (insn))
{
enum rtx_code code1 = GET_CODE (insn);
if (code1 == CALL_INSN)
SET_INSN_VOLATILE (insn);
else if (code1 == INSN || code1 == JUMP_INSN)
{
if (GET_CODE (PATTERN (insn)) != USE
&& volatile_refs_p (PATTERN (insn)))
SET_INSN_VOLATILE (insn);
else if (code1 == INSN && GET_CODE (PATTERN (insn)) == SET
&& SET_DEST (PATTERN (insn)) == stack_pointer_rtx
#ifdef STACK_GROWS_DOWNWARD
&& GET_CODE (SET_SRC (PATTERN (insn))) == MINUS
#else
&& GET_CODE (SET_SRC (PATTERN (insn))) == PLUS
#endif
&& XEXP (SET_SRC (PATTERN (insn)), 0) == stack_pointer_rtx)
SET_INSN_VOLATILE (insn);
else if (noop_move_p (insn))
{
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
}
}
if ( current_function_sp_is_unchanging
&& GET_RTX_CLASS (GET_CODE (insn)) == 'i')
note_stores (PATTERN (insn), notice_stack_pointer_modification);
}
}
static void
mark_regs_live_at_end (set)
regset set;
{
int i;
if (! EXIT_IGNORE_STACK
|| (! FRAME_POINTER_REQUIRED
&& ! current_function_calls_alloca
&& flag_omit_frame_pointer)
|| current_function_sp_is_unchanging)
{
SET_REGNO_REG_SET (set, STACK_POINTER_REGNUM);
}
if (! reload_completed || frame_pointer_needed)
{
SET_REGNO_REG_SET (set, FRAME_POINTER_REGNUM);
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
SET_REGNO_REG_SET (set, HARD_FRAME_POINTER_REGNUM);
#endif
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[i]
#ifdef EPILOGUE_USES
|| EPILOGUE_USES (i)
#endif
)
SET_REGNO_REG_SET (set, i);
}
static void
life_analysis_1 (f, nregs, remove_dead_code)
rtx f;
int nregs;
int remove_dead_code;
{
int first_pass;
int changed;
register int i;
char save_regs_ever_live[FIRST_PSEUDO_REGISTER];
regset *new_live_at_end;
struct obstack flow_obstack;
gcc_obstack_init (&flow_obstack);
max_regno = nregs;
allocate_reg_life_data ();
allocate_bb_life_data ();
reg_next_use = (rtx *) alloca (nregs * sizeof (rtx));
memset (reg_next_use, 0, nregs * sizeof (rtx));
new_live_at_end = (regset *) alloca ((n_basic_blocks + 1) * sizeof (regset));
init_regset_vector (new_live_at_end, n_basic_blocks + 1, &flow_obstack);
for (i = 0; i < n_basic_blocks; ++i)
BASIC_BLOCK (i)->aux = new_live_at_end[i];
ENTRY_BLOCK_PTR->aux = new_live_at_end[i];
current_function_sp_is_unchanging = !current_function_calls_alloca;
record_volatile_insns (f);
if (n_basic_blocks > 0)
{
regset theend;
register edge e;
theend = EXIT_BLOCK_PTR->global_live_at_start;
mark_regs_live_at_end (theend);
for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
{
COPY_REG_SET (e->src->global_live_at_end, theend);
COPY_REG_SET ((regset) e->src->aux, theend);
}
}
if (reload_completed)
memcpy (save_regs_ever_live, regs_ever_live, sizeof (regs_ever_live));
memset (regs_ever_live, 0, sizeof regs_ever_live);
first_pass = 1;
changed = 1;
while (changed)
{
changed = 0;
for (i = n_basic_blocks - 1; i >= 0; i--)
{
basic_block bb = BASIC_BLOCK (i);
int consider = first_pass;
int must_rescan = first_pass;
register int j;
if (!first_pass)
{
EXECUTE_IF_AND_COMPL_IN_REG_SET
((regset) bb->aux, bb->global_live_at_end, 0, j,
{
consider = 1;
if (REGNO_REG_SET_P (bb->local_set, j))
{
must_rescan = 1;
goto done;
}
});
done:
if (! consider)
continue;
}
changed = 1;
if (! must_rescan)
{
IOR_AND_COMPL_REG_SET (bb->global_live_at_start,
(regset) bb->aux,
bb->global_live_at_end);
IOR_AND_COMPL_REG_SET (bb->global_live_at_end,
(regset) bb->aux,
bb->global_live_at_end);
}
else
{
COPY_REG_SET (bb->global_live_at_end, (regset) bb->aux);
COPY_REG_SET (bb->global_live_at_start,
bb->global_live_at_end);
propagate_block (bb->global_live_at_start,
bb->head, bb->end, 0,
first_pass ? bb->local_set : (regset) 0,
i, remove_dead_code);
}
{
register edge e;
for (e = bb->pred; e ; e = e->pred_next)
IOR_REG_SET ((regset) e->src->aux, bb->global_live_at_start);
}
#ifdef USE_C_ALLOCA
alloca (0);
#endif
}
first_pass = 0;
}
if (n_basic_blocks > 0)
EXECUTE_IF_SET_IN_REG_SET (BASIC_BLOCK (0)->global_live_at_start,
FIRST_PSEUDO_REGISTER, i,
{
REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL;
});
for (i = 0; i < n_basic_blocks; i++)
{
basic_block bb = BASIC_BLOCK (i);
propagate_block ((regset) bb->aux, bb->head, bb->end, 1, (regset) 0, i, remove_dead_code);
#ifdef USE_C_ALLOCA
alloca (0);
#endif
}
EXECUTE_IF_SET_IN_REG_SET (regs_live_at_setjmp,
FIRST_PSEUDO_REGISTER, i,
{
if (regno_reg_rtx[i] != 0)
{
REG_LIVE_LENGTH (i) = -1;
REG_BASIC_BLOCK (i) = -1;
}
});
if (reload_completed)
memcpy (regs_ever_live, save_regs_ever_live, sizeof (regs_ever_live));
free_regset_vector (new_live_at_end, n_basic_blocks);
obstack_free (&flow_obstack, NULL_PTR);
for (i = 0; i < n_basic_blocks; ++i)
BASIC_BLOCK (i)->aux = NULL;
ENTRY_BLOCK_PTR->aux = NULL;
}
void
allocate_bb_life_data ()
{
register int i;
for (i = 0; i < n_basic_blocks; i++)
{
basic_block bb = BASIC_BLOCK (i);
bb->local_set = OBSTACK_ALLOC_REG_SET (function_obstack);
bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (function_obstack);
bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (function_obstack);
}
ENTRY_BLOCK_PTR->global_live_at_end
= OBSTACK_ALLOC_REG_SET (function_obstack);
EXIT_BLOCK_PTR->global_live_at_start
= OBSTACK_ALLOC_REG_SET (function_obstack);
regs_live_at_setjmp = OBSTACK_ALLOC_REG_SET (function_obstack);
}
void
allocate_reg_life_data ()
{
int i;
allocate_reg_info (max_regno, FALSE, FALSE);
for (i = 0; i < max_regno; i++)
REG_N_SETS (i) = 0;
}
static void
init_regset_vector (vector, nelts, alloc_obstack)
regset *vector;
int nelts;
struct obstack *alloc_obstack;
{
register int i;
for (i = 0; i < nelts; i++)
{
vector[i] = OBSTACK_ALLOC_REG_SET (alloc_obstack);
CLEAR_REG_SET (vector[i]);
}
}
void
free_regset_vector (vector, nelts)
regset *vector;
int nelts;
{
register int i;
for (i = 0; i < nelts; i++)
FREE_REG_SET (vector[i]);
}
static void
propagate_block (old, first, last, final, significant, bnum, remove_dead_code)
register regset old;
rtx first;
rtx last;
int final;
regset significant;
int bnum;
int remove_dead_code;
{
register rtx insn;
rtx prev;
regset live;
regset dead;
loop_depth = BASIC_BLOCK (bnum)->loop_depth;
dead = ALLOCA_REG_SET ();
live = ALLOCA_REG_SET ();
cc0_live = 0;
mem_set_list = NULL_RTX;
if (final)
{
register int i;
EXECUTE_IF_SET_IN_REG_SET (old, 0, i,
{
REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL;
});
}
for (insn = last; ; insn = prev)
{
prev = PREV_INSN (insn);
if (GET_CODE (insn) == NOTE)
{
if (final && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
IOR_REG_SET (regs_live_at_setjmp, old);
}
else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
register int i;
rtx note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
int insn_is_dead = 0;
int libcall_is_dead = 0;
if (remove_dead_code)
{
insn_is_dead = (insn_dead_p (PATTERN (insn), old, 0, REG_NOTES (insn))
&& ! INSN_VOLATILE (insn));
libcall_is_dead = (insn_is_dead && note != 0
&& libcall_dead_p (PATTERN (insn), old, note, insn));
}
if (final && insn_is_dead)
{
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
cc0_live = 0;
if (libcall_is_dead)
{
rtx first = XEXP (note, 0);
rtx p = insn;
while (INSN_DELETED_P (first))
first = NEXT_INSN (first);
while (p != first)
{
p = PREV_INSN (p);
PUT_CODE (p, NOTE);
NOTE_LINE_NUMBER (p) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (p) = 0;
}
}
goto flushed;
}
CLEAR_REG_SET (dead);
CLEAR_REG_SET (live);
#ifdef AUTO_INC_DEC
{
register rtx x = single_set (insn);
if (!reload_completed
&& final && x != 0
&& GET_CODE (SET_DEST (x)) == REG
&& (GET_CODE (SET_SRC (x)) == PLUS
|| GET_CODE (SET_SRC (x)) == MINUS)
&& XEXP (SET_SRC (x), 0) == SET_DEST (x)
&& GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
&& try_pre_increment_1 (insn))
goto flushed;
}
#endif
if (libcall_is_dead)
{
mark_set_regs (old, dead, PATTERN (insn), NULL_RTX, significant);
insn = XEXP (note, 0);
prev = PREV_INSN (insn);
}
else if (GET_CODE (PATTERN (insn)) == SET
&& SET_DEST (PATTERN (insn)) == stack_pointer_rtx
&& GET_CODE (SET_SRC (PATTERN (insn))) == PLUS
&& XEXP (SET_SRC (PATTERN (insn)), 0) == stack_pointer_rtx
&& GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == CONST_INT)
;
else
{
if (GET_CODE (insn) == CALL_INSN && final)
EXECUTE_IF_SET_IN_REG_SET (old, 0, i,
{
REG_N_CALLS_CROSSED (i)++;
});
mark_set_regs (old, dead, PATTERN (insn),
final ? insn : NULL_RTX, significant);
cc0_live = 0;
if (! insn_is_dead)
mark_used_regs (old, live, PATTERN (insn), final, insn);
#ifdef AUTO_INC_DEC
prev = PREV_INSN (insn);
#endif
if (! insn_is_dead && GET_CODE (insn) == CALL_INSN)
{
register int i;
rtx note;
for (note = CALL_INSN_FUNCTION_USAGE (insn);
note;
note = XEXP (note, 1))
if (GET_CODE (XEXP (note, 0)) == USE)
mark_used_regs (old, live, SET_DEST (XEXP (note, 0)),
final, insn);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (call_used_regs[i] && ! global_regs[i]
&& ! fixed_regs[i])
SET_REGNO_REG_SET (dead, i);
SET_REGNO_REG_SET (live, STACK_POINTER_REGNUM);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[i])
mark_used_regs (old, live,
gen_rtx_REG (reg_raw_mode[i], i),
final, insn);
mem_set_list = NULL_RTX;
}
AND_COMPL_REG_SET (old, dead);
IOR_REG_SET (old, live);
}
if (final)
EXECUTE_IF_SET_IN_REG_SET (old, 0, i,
{ REG_LIVE_LENGTH (i)++; });
}
flushed: ;
if (insn == first)
break;
}
FREE_REG_SET (dead);
FREE_REG_SET (live);
}
static int
insn_dead_p (x, needed, call_ok, notes)
rtx x;
regset needed;
int call_ok;
rtx notes ATTRIBUTE_UNUSED;
{
enum rtx_code code = GET_CODE (x);
#ifdef AUTO_INC_DEC
if (reload_completed)
{
for ( ; notes; notes = XEXP (notes, 1))
{
if (REG_NOTE_KIND (notes) == REG_INC)
{
int regno = REGNO (XEXP (notes, 0));
if ((regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
|| REGNO_REG_SET_P (needed, regno))
return 0;
}
}
}
#endif
if (code == SET)
{
rtx r = SET_DEST (x);
if (! call_ok && GET_CODE (SET_SRC (x)) == CALL)
return 0;
#ifdef HAVE_cc0
if (GET_CODE (r) == CC0)
return ! cc0_live;
#endif
if (GET_CODE (r) == MEM && ! MEM_VOLATILE_P (r))
{
rtx temp;
temp = mem_set_list;
while (temp)
{
if (rtx_equal_p (XEXP (temp, 0), r))
return 1;
temp = XEXP (temp, 1);
}
}
while (GET_CODE (r) == SUBREG || GET_CODE (r) == STRICT_LOW_PART
|| GET_CODE (r) == ZERO_EXTRACT)
r = SUBREG_REG (r);
if (GET_CODE (r) == REG)
{
int regno = REGNO (r);
if ((regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
|| (regno == FRAME_POINTER_REGNUM
&& (! reload_completed || frame_pointer_needed))
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
|| (regno == HARD_FRAME_POINTER_REGNUM
&& (! reload_completed || frame_pointer_needed))
#endif
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
|| (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
#endif
|| REGNO_REG_SET_P (needed, regno))
return 0;
if (regno < FIRST_PSEUDO_REGISTER)
{
int n = HARD_REGNO_NREGS (regno, GET_MODE (r));
while (--n > 0)
if (REGNO_REG_SET_P (needed, regno+n))
return 0;
}
return 1;
}
}
else if (code == PARALLEL)
{
int i = XVECLEN (x, 0);
for (i--; i >= 0; i--)
if (GET_CODE (XVECEXP (x, 0, i)) != CLOBBER
&& GET_CODE (XVECEXP (x, 0, i)) != USE
&& ! insn_dead_p (XVECEXP (x, 0, i), needed, call_ok, NULL_RTX))
return 0;
return 1;
}
else if (code == CLOBBER && GET_CODE (XEXP (x, 0)) == REG
&& REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER
&& ! REGNO_REG_SET_P (needed, REGNO (XEXP (x, 0))))
return 1;
return 0;
}
static int
libcall_dead_p (x, needed, note, insn)
rtx x;
regset needed;
rtx note;
rtx insn;
{
register RTX_CODE code = GET_CODE (x);
if (code == SET)
{
register rtx r = SET_SRC (x);
if (GET_CODE (r) == REG)
{
rtx call = XEXP (note, 0);
rtx call_pat;
register int i;
while (call != insn && GET_CODE (call) != CALL_INSN)
call = NEXT_INSN (call);
if (call == insn)
return 0;
call_pat = PATTERN (call);
if (GET_CODE (call_pat) == PARALLEL)
{
for (i = XVECLEN (call_pat, 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (call_pat, 0, i)) == SET
&& GET_CODE (SET_SRC (XVECEXP (call_pat, 0, i))) == CALL)
break;
if (i < 0)
return 0;
call_pat = XVECEXP (call_pat, 0, i);
}
return insn_dead_p (call_pat, needed, 1, REG_NOTES (call));
}
}
return 1;
}
int
regno_uninitialized (regno)
int regno;
{
if (n_basic_blocks == 0
|| (regno < FIRST_PSEUDO_REGISTER
&& (global_regs[regno]
|| fixed_regs[regno]
|| FUNCTION_ARG_REGNO_P (regno))))
return 0;
return REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start, regno);
}
int
regno_clobbered_at_setjmp (regno)
int regno;
{
if (n_basic_blocks == 0)
return 0;
return ((REG_N_SETS (regno) > 1
|| REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start, regno))
&& REGNO_REG_SET_P (regs_live_at_setjmp, regno));
}
static void
invalidate_mems_from_autoinc (insn)
rtx insn;
{
rtx note = REG_NOTES (insn);
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
{
if (REG_NOTE_KIND (note) == REG_INC)
{
rtx temp = mem_set_list;
rtx prev = NULL_RTX;
while (temp)
{
if (reg_overlap_mentioned_p (XEXP (note, 0), XEXP (temp, 0)))
{
if (prev)
XEXP (prev, 1) = XEXP (temp, 1);
else
mem_set_list = XEXP (temp, 1);
}
else
prev = temp;
temp = XEXP (temp, 1);
}
}
}
}
static void
mark_set_regs (needed, dead, x, insn, significant)
regset needed;
regset dead;
rtx x;
rtx insn;
regset significant;
{
register RTX_CODE code = GET_CODE (x);
if (code == SET || code == CLOBBER)
mark_set_1 (needed, dead, x, insn, significant);
else if (code == PARALLEL)
{
register int i;
for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
{
code = GET_CODE (XVECEXP (x, 0, i));
if (code == SET || code == CLOBBER)
mark_set_1 (needed, dead, XVECEXP (x, 0, i), insn, significant);
}
}
}
static void
mark_set_1 (needed, dead, x, insn, significant)
regset needed;
regset dead;
rtx x;
rtx insn;
regset significant;
{
register int regno;
register rtx reg = SET_DEST (x);
if (GET_CODE (reg) == PARALLEL
&& GET_MODE (reg) == BLKmode)
{
register int i;
for (i = XVECLEN (reg, 0) - 1; i >= 0; i--)
mark_set_1 (needed, dead, XVECEXP (reg, 0, i), insn, significant);
return;
}
while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT
|| GET_CODE (reg) == SIGN_EXTRACT
|| GET_CODE (reg) == STRICT_LOW_PART)
reg = XEXP (reg, 0);
if (GET_CODE (reg) == MEM
|| GET_CODE (reg) == REG)
{
rtx temp = mem_set_list;
rtx prev = NULL_RTX;
while (temp)
{
if ((GET_CODE (reg) == MEM
&& output_dependence (XEXP (temp, 0), reg))
|| (GET_CODE (reg) == REG
&& reg_overlap_mentioned_p (reg, XEXP (temp, 0))))
{
if (prev)
XEXP (prev, 1) = XEXP (temp, 1);
else
mem_set_list = XEXP (temp, 1);
}
else
prev = temp;
temp = XEXP (temp, 1);
}
}
if (insn && GET_CODE (reg) == MEM)
invalidate_mems_from_autoinc (insn);
if (GET_CODE (reg) == MEM && ! side_effects_p (reg)
&& GET_MODE (reg) != BLKmode
&& ! reg_mentioned_p (stack_pointer_rtx, reg))
mem_set_list = gen_rtx_EXPR_LIST (VOIDmode, reg, mem_set_list);
if (GET_CODE (reg) == REG
&& (regno = REGNO (reg), ! (regno == FRAME_POINTER_REGNUM
&& (! reload_completed || frame_pointer_needed)))
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
&& ! (regno == HARD_FRAME_POINTER_REGNUM
&& (! reload_completed || frame_pointer_needed))
#endif
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
&& ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
#endif
&& ! (regno < FIRST_PSEUDO_REGISTER && global_regs[regno]))
{
int some_needed = REGNO_REG_SET_P (needed, regno);
int some_not_needed = ! some_needed;
if (significant)
SET_REGNO_REG_SET (significant, regno);
SET_REGNO_REG_SET (dead, regno);
if (regno < FIRST_PSEUDO_REGISTER)
{
int n;
if (regno == STACK_POINTER_REGNUM)
return;
n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (--n > 0)
{
int regno_n = regno + n;
int needed_regno = REGNO_REG_SET_P (needed, regno_n);
if (significant)
SET_REGNO_REG_SET (significant, regno_n);
SET_REGNO_REG_SET (dead, regno_n);
some_needed |= needed_regno;
some_not_needed |= ! needed_regno;
}
}
if (insn)
{
register rtx y = reg_next_use[regno];
register int blocknum = BLOCK_NUM (insn);
if (regno < FIRST_PSEUDO_REGISTER)
{
register int i;
int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
for (i = regno; i < endregno; i++)
{
reg_next_use[i] = 0;
regs_ever_live[i] = 1;
REG_N_SETS (i)++;
}
}
else
{
reg_next_use[regno] = 0;
if (REG_BASIC_BLOCK (regno) == REG_BLOCK_UNKNOWN)
REG_BASIC_BLOCK (regno) = blocknum;
else if (REG_BASIC_BLOCK (regno) != blocknum)
REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
REG_N_SETS (regno)++;
REG_N_REFS (regno) += loop_depth;
REG_LIVE_LENGTH (regno)++;
}
if (! some_not_needed)
{
if (y && (BLOCK_NUM (y) == blocknum)
&& (regno >= FIRST_PSEUDO_REGISTER
|| asm_noperands (PATTERN (y)) < 0))
LOG_LINKS (y)
= gen_rtx_INSN_LIST (VOIDmode, insn, LOG_LINKS (y));
}
else if (! some_needed)
{
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (insn));
REG_N_DEATHS (REGNO (reg))++;
}
else
{
int i;
for (i = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1;
i >= 0; i--)
if (!REGNO_REG_SET_P (needed, regno + i))
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_UNUSED,
gen_rtx_REG (reg_raw_mode[regno + i],
regno + i),
REG_NOTES (insn));
}
}
}
else if (GET_CODE (reg) == REG)
reg_next_use[regno] = 0;
else if (GET_CODE (reg) == SCRATCH && insn != 0)
{
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (insn));
}
}
#ifdef AUTO_INC_DEC
static void
find_auto_inc (needed, x, insn)
regset needed;
rtx x;
rtx insn;
{
rtx addr = XEXP (x, 0);
HOST_WIDE_INT offset = 0;
rtx set;
if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 1)) == CONST_INT)
offset = INTVAL (XEXP (addr, 1)), addr = XEXP (addr, 0);
if (GET_CODE (addr) == REG)
{
register rtx y;
register int size = GET_MODE_SIZE (GET_MODE (x));
rtx use;
rtx incr;
int regno = REGNO (addr);
if ((incr = reg_next_use[regno]) != 0
&& (set = single_set (incr)) != 0
&& GET_CODE (set) == SET
&& BLOCK_NUM (incr) == BLOCK_NUM (insn)
&& GET_CODE (insn) != JUMP_INSN
&& (y = SET_SRC (set), GET_CODE (y) == PLUS)
&& XEXP (y, 0) == addr
&& GET_CODE (XEXP (y, 1)) == CONST_INT
&& ((HAVE_POST_INCREMENT
&& (INTVAL (XEXP (y, 1)) == size && offset == 0))
|| (HAVE_POST_DECREMENT
&& (INTVAL (XEXP (y, 1)) == - size && offset == 0))
|| (HAVE_PRE_INCREMENT
&& (INTVAL (XEXP (y, 1)) == size && offset == size))
|| (HAVE_PRE_DECREMENT
&& (INTVAL (XEXP (y, 1)) == - size && offset == - size)))
&& (use = find_use_as_address (PATTERN (insn), addr, offset),
use != 0 && use != (rtx) 1))
{
rtx q = SET_DEST (set);
enum rtx_code inc_code = (INTVAL (XEXP (y, 1)) == size
? (offset ? PRE_INC : POST_INC)
: (offset ? PRE_DEC : POST_DEC));
if (dead_or_set_p (incr, addr))
{
if (! validate_change (insn, &XEXP (x, 0),
gen_rtx_fmt_e (inc_code, Pmode, addr),
0))
return;
}
else if (GET_CODE (q) == REG
&& ! reg_used_between_p (q, PREV_INSN (insn), incr)
&& ! reg_set_between_p (q, PREV_INSN (insn), incr))
{
rtx insns, temp;
basic_block bb;
start_sequence ();
emit_move_insn (q, addr);
insns = get_insns ();
end_sequence ();
bb = BLOCK_FOR_INSN (insn);
for (temp = insns; temp; temp = NEXT_INSN (temp))
set_block_for_insn (temp, bb);
validate_change (insn, &XEXP (x, 0),
gen_rtx_fmt_e (inc_code, Pmode, q),
1);
validate_change (incr, &XEXP (y, 0), q, 1);
if (! apply_change_group ())
return;
emit_insns_before (insns, insn);
if (BLOCK_FOR_INSN (insn)->head == insn)
BLOCK_FOR_INSN (insn)->head = insns;
if (GET_CODE (PREV_INSN (insn)) == INSN
&& GET_CODE (PATTERN (PREV_INSN (insn))) == SET
&& SET_SRC (PATTERN (PREV_INSN (insn))) == addr)
reg_next_use[regno] = PREV_INSN (insn);
else
reg_next_use[regno] = 0;
addr = q;
regno = REGNO (q);
SET_REGNO_REG_SET (needed, regno);
for (temp = insn; temp != incr; temp = NEXT_INSN (temp))
if (GET_CODE (temp) == CALL_INSN)
REG_N_CALLS_CROSSED (regno)++;
}
else
return;
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_INC, addr, REG_NOTES (insn));
if (! validate_change (incr, &SET_SRC (set), addr, 0))
abort ();
if (SET_DEST (set) == addr)
{
PUT_CODE (incr, NOTE);
NOTE_LINE_NUMBER (incr) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (incr) = 0;
}
if (regno >= FIRST_PSEUDO_REGISTER)
{
REG_N_REFS (regno) += loop_depth;
REG_N_SETS (regno)++;
}
}
}
}
#endif
static void
mark_used_regs (needed, live, x, final, insn)
regset needed;
regset live;
rtx x;
int final;
rtx insn;
{
register RTX_CODE code;
register int regno;
int i;
retry:
code = GET_CODE (x);
switch (code)
{
case LABEL_REF:
case SYMBOL_REF:
case CONST_INT:
case CONST:
case CONST_DOUBLE:
case PC:
case ADDR_VEC:
case ADDR_DIFF_VEC:
return;
#ifdef HAVE_cc0
case CC0:
cc0_live = 1;
return;
#endif
case CLOBBER:
if (GET_CODE (XEXP (x, 0)) == MEM)
mark_used_regs (needed, live, XEXP (XEXP (x, 0), 0), final, insn);
return;
case MEM:
if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
;
else
{
rtx temp = mem_set_list;
rtx prev = NULL_RTX;
while (temp)
{
if (anti_dependence (XEXP (temp, 0), x))
{
if (prev)
XEXP (prev, 1) = XEXP (temp, 1);
else
mem_set_list = XEXP (temp, 1);
}
else
prev = temp;
temp = XEXP (temp, 1);
}
}
if (insn)
invalidate_mems_from_autoinc (insn);
#ifdef AUTO_INC_DEC
if (final)
find_auto_inc (needed, x, insn);
#endif
break;
case SUBREG:
if (GET_CODE (SUBREG_REG (x)) == REG
&& REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER
&& (GET_MODE_SIZE (GET_MODE (x))
!= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
REG_CHANGES_SIZE (REGNO (SUBREG_REG (x))) = 1;
x = SUBREG_REG (x);
if (GET_CODE (x) != REG)
{
mark_used_regs (needed, live, x, final, insn);
return;
}
case REG:
regno = REGNO (x);
{
int some_needed = REGNO_REG_SET_P (needed, regno);
int some_not_needed = ! some_needed;
SET_REGNO_REG_SET (live, regno);
if (regno < FIRST_PSEUDO_REGISTER)
{
int n;
if (regno == STACK_POINTER_REGNUM
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
|| (regno == HARD_FRAME_POINTER_REGNUM
&& (! reload_completed || frame_pointer_needed))
#endif
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
|| (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
#endif
|| (regno == FRAME_POINTER_REGNUM
&& (! reload_completed || frame_pointer_needed)))
{
if (! TEST_HARD_REG_BIT (elim_reg_set, regno))
regs_ever_live[regno] = 1;
return;
}
if (global_regs[regno])
{
if (final)
reg_next_use[regno] = insn;
return;
}
n = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (--n > 0)
{
int regno_n = regno + n;
int needed_regno = REGNO_REG_SET_P (needed, regno_n);
SET_REGNO_REG_SET (live, regno_n);
some_needed |= needed_regno;
some_not_needed |= ! needed_regno;
}
}
if (final)
{
reg_next_use[regno] = insn;
if (regno < FIRST_PSEUDO_REGISTER)
{
i = HARD_REGNO_NREGS (regno, GET_MODE (x));
if (i == 0)
i = 1;
do
regs_ever_live[regno + --i] = 1;
while (i > 0);
}
else
{
register int blocknum = BLOCK_NUM (insn);
if (REG_BASIC_BLOCK (regno) == REG_BLOCK_UNKNOWN)
REG_BASIC_BLOCK (regno) = blocknum;
else if (REG_BASIC_BLOCK (regno) != blocknum)
REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
REG_N_REFS (regno) += loop_depth;
}
if (some_not_needed
&& ! dead_or_set_p (insn, x)
#if 0
&& (regno >= FIRST_PSEUDO_REGISTER || ! fixed_regs[regno])
#endif
)
{
if (regno < FIRST_PSEUDO_REGISTER
&& HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
{
int n = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (--n >= 0)
some_needed |= dead_or_set_regno_p (insn, regno + n);
}
if (! some_needed)
{
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_DEAD, x, REG_NOTES (insn));
REG_N_DEATHS (regno)++;
}
else
{
int i;
for (i = HARD_REGNO_NREGS (regno, GET_MODE (x)) - 1;
i >= 0; i--)
if (!REGNO_REG_SET_P (needed, regno + i)
&& ! dead_or_set_regno_p (insn, regno + i))
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_DEAD,
gen_rtx_REG (reg_raw_mode[regno + i],
regno + i),
REG_NOTES (insn));
}
}
}
}
return;
case SET:
{
register rtx testreg = SET_DEST (x);
int mark_dest = 0;
if (GET_CODE (testreg) == MEM)
{
#ifdef AUTO_INC_DEC
if (final)
find_auto_inc (needed, testreg, insn);
#endif
mark_used_regs (needed, live, XEXP (testreg, 0), final, insn);
mark_used_regs (needed, live, SET_SRC (x), final, insn);
return;
}
while (GET_CODE (testreg) == STRICT_LOW_PART
|| GET_CODE (testreg) == ZERO_EXTRACT
|| GET_CODE (testreg) == SIGN_EXTRACT
|| GET_CODE (testreg) == SUBREG)
{
if (GET_CODE (testreg) == SUBREG
&& GET_CODE (SUBREG_REG (testreg)) == REG
&& REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER
&& (GET_MODE_SIZE (GET_MODE (testreg))
!= GET_MODE_SIZE (GET_MODE (SUBREG_REG (testreg)))))
REG_CHANGES_SIZE (REGNO (SUBREG_REG (testreg))) = 1;
if (GET_CODE (testreg) == SUBREG
&& !(REG_SIZE (SUBREG_REG (testreg)) > REG_SIZE (testreg)))
;
else
mark_dest = 1;
testreg = XEXP (testreg, 0);
}
if ((GET_CODE (testreg) == PARALLEL
&& GET_MODE (testreg) == BLKmode)
|| (GET_CODE (testreg) == REG
&& (regno = REGNO (testreg), ! (regno == FRAME_POINTER_REGNUM
&& (! reload_completed || frame_pointer_needed)))
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
&& ! (regno == HARD_FRAME_POINTER_REGNUM
&& (! reload_completed || frame_pointer_needed))
#endif
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
&& ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
#endif
))
{
mark_used_regs (needed, live, SET_SRC (x), final, insn);
if (mark_dest)
mark_used_regs (needed, live, SET_DEST (x), final, insn);
return;
}
}
break;
case RETURN:
if (! EXIT_IGNORE_STACK
|| (! FRAME_POINTER_REQUIRED
&& ! current_function_calls_alloca
&& flag_omit_frame_pointer)
|| current_function_sp_is_unchanging)
SET_REGNO_REG_SET (live, STACK_POINTER_REGNUM);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[i]
#ifdef EPILOGUE_USES
|| EPILOGUE_USES (i)
#endif
)
SET_REGNO_REG_SET (live, i);
break;
case ASM_OPERANDS:
case UNSPEC_VOLATILE:
case TRAP_IF:
case ASM_INPUT:
{
if (code != ASM_OPERANDS || MEM_VOLATILE_P (x))
mem_set_list = NULL_RTX;
if (code == ASM_OPERANDS)
{
int j;
for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++)
mark_used_regs (needed, live, ASM_OPERANDS_INPUT (x, j),
final, insn);
}
break;
}
default:
break;
}
{
register char *fmt = GET_RTX_FORMAT (code);
register int i;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
if (i == 0)
{
x = XEXP (x, 0);
goto retry;
}
mark_used_regs (needed, live, XEXP (x, i), final, insn);
}
else if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (x, i); j++)
mark_used_regs (needed, live, XVECEXP (x, i, j), final, insn);
}
}
}
}
#ifdef AUTO_INC_DEC
static int
try_pre_increment_1 (insn)
rtx insn;
{
rtx x = single_set (insn);
HOST_WIDE_INT amount = ((GET_CODE (SET_SRC (x)) == PLUS ? 1 : -1)
* INTVAL (XEXP (SET_SRC (x), 1)));
int regno = REGNO (SET_DEST (x));
rtx y = reg_next_use[regno];
if (y != 0
&& BLOCK_NUM (y) == BLOCK_NUM (insn)
&& ! dead_or_set_p (y, SET_DEST (x))
&& try_pre_increment (y, SET_DEST (x), amount))
{
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
if (regno >= FIRST_PSEUDO_REGISTER)
{
REG_N_REFS (regno) += loop_depth;
REG_N_SETS (regno)++;
}
return 1;
}
return 0;
}
static int
try_pre_increment (insn, reg, amount)
rtx insn, reg;
HOST_WIDE_INT amount;
{
register rtx use;
int pre_ok = 0;
int post_ok = 0;
int do_post = 0;
if (HAVE_PRE_INCREMENT && amount > 0)
pre_ok = 1;
if (HAVE_POST_INCREMENT && amount > 0)
post_ok = 1;
if (HAVE_PRE_DECREMENT && amount < 0)
pre_ok = 1;
if (HAVE_POST_DECREMENT && amount < 0)
post_ok = 1;
if (! (pre_ok || post_ok))
return 0;
if (GET_CODE (insn) == JUMP_INSN)
return 0;
use = 0;
if (pre_ok)
use = find_use_as_address (PATTERN (insn), reg, 0);
if (post_ok && (use == 0 || use == (rtx) 1))
{
use = find_use_as_address (PATTERN (insn), reg, -amount);
do_post = 1;
}
if (use == 0 || use == (rtx) 1)
return 0;
if (GET_MODE_SIZE (GET_MODE (use)) != (amount > 0 ? amount : - amount))
return 0;
if (! validate_change (insn, &XEXP (use, 0),
gen_rtx_fmt_e (amount > 0
? (do_post ? POST_INC : PRE_INC)
: (do_post ? POST_DEC : PRE_DEC),
Pmode, reg), 0))
return 0;
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, reg, REG_NOTES (insn));
return 1;
}
#endif
rtx
find_use_as_address (x, reg, plusconst)
register rtx x;
rtx reg;
HOST_WIDE_INT plusconst;
{
enum rtx_code code = GET_CODE (x);
char *fmt = GET_RTX_FORMAT (code);
register int i;
register rtx value = 0;
register rtx tem;
if (code == MEM && XEXP (x, 0) == reg && plusconst == 0)
return x;
if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS
&& XEXP (XEXP (x, 0), 0) == reg
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (x, 0), 1)) == plusconst)
return x;
if (code == SIGN_EXTRACT || code == ZERO_EXTRACT)
{
if (find_use_as_address (XEXP (x, 0), reg, 0) != 0)
return (rtx) (HOST_WIDE_INT) 1;
}
if (x == reg)
return (rtx) (HOST_WIDE_INT) 1;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
tem = find_use_as_address (XEXP (x, i), reg, plusconst);
if (value == 0)
value = tem;
else if (tem != 0)
return (rtx) (HOST_WIDE_INT) 1;
}
if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
{
tem = find_use_as_address (XVECEXP (x, i, j), reg, plusconst);
if (value == 0)
value = tem;
else if (tem != 0)
return (rtx) (HOST_WIDE_INT) 1;
}
}
}
return value;
}
void
dump_flow_info (file)
FILE *file;
{
register int i;
static char *reg_class_names[] = REG_CLASS_NAMES;
fprintf (file, "%d registers.\n", max_regno);
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
if (REG_N_REFS (i))
{
enum reg_class class, altclass;
fprintf (file, "\nRegister %d used %d times across %d insns",
i, REG_N_REFS (i), REG_LIVE_LENGTH (i));
if (REG_BASIC_BLOCK (i) >= 0)
fprintf (file, " in block %d", REG_BASIC_BLOCK (i));
if (REG_N_SETS (i))
fprintf (file, "; set %d time%s", REG_N_SETS (i),
(REG_N_SETS (i) == 1) ? "" : "s");
if (REG_USERVAR_P (regno_reg_rtx[i]))
fprintf (file, "; user var");
if (REG_N_DEATHS (i) != 1)
fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
if (REG_N_CALLS_CROSSED (i) == 1)
fprintf (file, "; crosses 1 call");
else if (REG_N_CALLS_CROSSED (i))
fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i));
if (PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD)
fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i));
class = reg_preferred_class (i);
altclass = reg_alternate_class (i);
if (class != GENERAL_REGS || altclass != ALL_REGS)
{
if (altclass == ALL_REGS || class == ALL_REGS)
fprintf (file, "; pref %s", reg_class_names[(int) class]);
else if (altclass == NO_REGS)
fprintf (file, "; %s or none", reg_class_names[(int) class]);
else
fprintf (file, "; pref %s, else %s",
reg_class_names[(int) class],
reg_class_names[(int) altclass]);
}
if (REGNO_POINTER_FLAG (i))
fprintf (file, "; pointer");
fprintf (file, ".\n");
}
fprintf (file, "\n%d basic blocks.\n", n_basic_blocks);
for (i = 0; i < n_basic_blocks; i++)
{
register basic_block bb = BASIC_BLOCK (i);
register int regno;
register edge e;
fprintf (file, "\nBasic block %d: first insn %d, last %d.\n",
i, INSN_UID (bb->head), INSN_UID (bb->end));
fprintf (file, "Predecessors: ");
for (e = bb->pred; e ; e = e->pred_next)
dump_edge_info (file, e, 0);
fprintf (file, "\nSuccessors: ");
for (e = bb->succ; e ; e = e->succ_next)
dump_edge_info (file, e, 1);
fprintf (file, "\nRegisters live at start:");
if (bb->global_live_at_start)
{
for (regno = 0; regno < max_regno; regno++)
if (REGNO_REG_SET_P (bb->global_live_at_start, regno))
fprintf (file, " %d", regno);
}
else
fprintf (file, " n/a");
fprintf (file, "\nRegisters live at end:");
if (bb->global_live_at_end)
{
for (regno = 0; regno < max_regno; regno++)
if (REGNO_REG_SET_P (bb->global_live_at_end, regno))
fprintf (file, " %d", regno);
}
else
fprintf (file, " n/a");
putc('\n', file);
}
putc('\n', file);
}
static void
dump_edge_info (file, e, do_succ)
FILE *file;
edge e;
int do_succ;
{
basic_block side = (do_succ ? e->dest : e->src);
if (side == ENTRY_BLOCK_PTR)
fputs (" ENTRY", file);
else if (side == EXIT_BLOCK_PTR)
fputs (" EXIT", file);
else
fprintf (file, " %d", side->index);
if (e->flags)
{
static char * bitnames[] = {
"fallthru", "crit", "ab", "abcall", "eh", "fake"
};
int comma = 0;
int i, flags = e->flags;
fputc (' ', file);
fputc ('(', file);
for (i = 0; flags; i++)
if (flags & (1 << i))
{
flags &= ~(1 << i);
if (comma)
fputc (',', file);
if (i < (int)(sizeof (bitnames) / sizeof (*bitnames)))
fputs (bitnames[i], file);
else
fprintf (file, "%d", i);
comma = 1;
}
fputc (')', file);
}
}
void
print_rtl_with_bb (outf, rtx_first)
FILE *outf;
rtx rtx_first;
{
register rtx tmp_rtx;
if (rtx_first == 0)
fprintf (outf, "(nil)\n");
else
{
int i;
enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
int max_uid = get_max_uid ();
basic_block *start = (basic_block *)
alloca (max_uid * sizeof (basic_block));
basic_block *end = (basic_block *)
alloca (max_uid * sizeof (basic_block));
enum bb_state *in_bb_p = (enum bb_state *)
alloca (max_uid * sizeof (enum bb_state));
memset (start, 0, max_uid * sizeof (basic_block));
memset (end, 0, max_uid * sizeof (basic_block));
memset (in_bb_p, 0, max_uid * sizeof (enum bb_state));
for (i = n_basic_blocks - 1; i >= 0; i--)
{
basic_block bb = BASIC_BLOCK (i);
rtx x;
start[INSN_UID (bb->head)] = bb;
end[INSN_UID (bb->end)] = bb;
for (x = bb->head; x != NULL_RTX; x = NEXT_INSN (x))
{
enum bb_state state = IN_MULTIPLE_BB;
if (in_bb_p[INSN_UID(x)] == NOT_IN_BB)
state = IN_ONE_BB;
in_bb_p[INSN_UID(x)] = state;
if (x == bb->end)
break;
}
}
for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx))
{
int did_output;
basic_block bb;
if ((bb = start[INSN_UID (tmp_rtx)]) != NULL)
{
fprintf (outf, ";; Start of basic block %d, registers live:",
bb->index);
EXECUTE_IF_SET_IN_REG_SET (bb->global_live_at_start, 0, i,
{
fprintf (outf, " %d", i);
if (i < FIRST_PSEUDO_REGISTER)
fprintf (outf, " [%s]",
reg_names[i]);
});
putc ('\n', outf);
}
if (in_bb_p[INSN_UID(tmp_rtx)] == NOT_IN_BB
&& GET_CODE (tmp_rtx) != NOTE
&& GET_CODE (tmp_rtx) != BARRIER
&& ! obey_regdecls)
fprintf (outf, ";; Insn is not within a basic block\n");
else if (in_bb_p[INSN_UID(tmp_rtx)] == IN_MULTIPLE_BB)
fprintf (outf, ";; Insn is in multiple basic blocks\n");
did_output = print_rtl_single (outf, tmp_rtx);
if ((bb = end[INSN_UID (tmp_rtx)]) != NULL)
fprintf (outf, ";; End of basic block %d\n", bb->index);
if (did_output)
putc ('\n', outf);
}
}
}
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];
}
static int_list_block *pred_int_list_blocks;
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;
}
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);
}
*blk_list = NULL;
}
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]++;
}
}
void
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 i, n = n_basic_blocks;
edge e;
memset (s_preds, 0, n_basic_blocks * sizeof (int_list_ptr));
memset (s_succs, 0, n_basic_blocks * sizeof (int_list_ptr));
memset (num_preds, 0, n_basic_blocks * sizeof (int));
memset (num_succs, 0, n_basic_blocks * sizeof (int));
for (i = 0; i < n; ++i)
{
basic_block bb = BASIC_BLOCK (i);
for (e = bb->succ; e ; e = e->succ_next)
add_pred_succ (i, e->dest->index, s_preds, s_succs,
num_preds, num_succs);
}
for (e = ENTRY_BLOCK_PTR->succ; e ; e = e->succ_next)
add_pred_succ (ENTRY_BLOCK, e->dest->index, s_preds, s_succs,
num_preds, num_succs);
}
void
dump_bb_data (file, preds, succs, live_info)
FILE *file;
int_list_ptr *preds;
int_list_ptr *succs;
int live_info;
{
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);
}
if (live_info)
{
int regno;
fprintf (file, "\nRegisters live at start:");
for (regno = 0; regno < max_regno; regno++)
if (REGNO_REG_SET_P (BASIC_BLOCK (bb)->global_live_at_start, regno))
fprintf (file, " %d", regno);
fprintf (file, "\n");
}
fprintf (file, "\n");
}
fprintf (file, "\n");
}
void
free_bb_mem ()
{
free_int_list (&pred_int_list_blocks);
}
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);
}
void
compute_immediate_dominators (idom, dominators)
int *idom;
sbitmap *dominators;
{
sbitmap *tmp;
int b;
tmp = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
for (b = n_basic_blocks; --b >= 0; )
{
sbitmap_copy (tmp[b], dominators[b]);
RESET_BIT (tmp[b], b);
}
for (b = n_basic_blocks; --b >= 0; )
{
sbitmap tmp_b = tmp[b];
int s;
for (s = n_basic_blocks; --s >= 0; )
if (TEST_BIT (tmp_b, s))
sbitmap_difference (tmp_b, tmp_b, tmp[s]);
}
for (b = n_basic_blocks; --b >= 0; )
{
int t;
EXECUTE_IF_SET_IN_SBITMAP (tmp[b], 0, t, { idom[b] = t; });
}
sbitmap_vector_free (tmp);
}
static void
count_reg_sets_1 (x)
rtx x;
{
register int regno;
register rtx reg = SET_DEST (x);
while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT
|| GET_CODE (reg) == SIGN_EXTRACT
|| GET_CODE (reg) == STRICT_LOW_PART)
reg = XEXP (reg, 0);
if (GET_CODE (reg) == PARALLEL
&& GET_MODE (reg) == BLKmode)
{
register int i;
for (i = XVECLEN (reg, 0) - 1; i >= 0; i--)
count_reg_sets_1 (XVECEXP (reg, 0, i));
return;
}
if (GET_CODE (reg) == REG)
{
regno = REGNO (reg);
if (regno >= FIRST_PSEUDO_REGISTER)
{
REG_N_SETS (regno)++;
REG_N_REFS (regno) += loop_depth;
}
}
}
static void
count_reg_sets (x)
rtx x;
{
register RTX_CODE code = GET_CODE (x);
if (code == SET || code == CLOBBER)
count_reg_sets_1 (x);
else if (code == PARALLEL)
{
register int i;
for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
{
code = GET_CODE (XVECEXP (x, 0, i));
if (code == SET || code == CLOBBER)
count_reg_sets_1 (XVECEXP (x, 0, i));
}
}
}
static void
count_reg_references (x)
rtx x;
{
register RTX_CODE code;
retry:
code = GET_CODE (x);
switch (code)
{
case LABEL_REF:
case SYMBOL_REF:
case CONST_INT:
case CONST:
case CONST_DOUBLE:
case PC:
case ADDR_VEC:
case ADDR_DIFF_VEC:
case ASM_INPUT:
return;
#ifdef HAVE_cc0
case CC0:
return;
#endif
case CLOBBER:
if (GET_CODE (XEXP (x, 0)) == MEM)
count_reg_references (XEXP (XEXP (x, 0), 0));
return;
case SUBREG:
x = SUBREG_REG (x);
if (GET_CODE (x) != REG)
{
count_reg_references (x);
return;
}
case REG:
if (REGNO (x) >= FIRST_PSEUDO_REGISTER)
REG_N_REFS (REGNO (x)) += loop_depth;
return;
case SET:
{
register rtx testreg = SET_DEST (x);
int mark_dest = 0;
if (GET_CODE (testreg) == MEM)
{
count_reg_references (XEXP (testreg, 0));
count_reg_references (SET_SRC (x));
return;
}
while (GET_CODE (testreg) == STRICT_LOW_PART
|| GET_CODE (testreg) == ZERO_EXTRACT
|| GET_CODE (testreg) == SIGN_EXTRACT
|| GET_CODE (testreg) == SUBREG)
{
if (GET_CODE (testreg) == SUBREG
&& !(REG_SIZE (SUBREG_REG (testreg)) > REG_SIZE (testreg)))
;
else
mark_dest = 1;
testreg = XEXP (testreg, 0);
}
if ((GET_CODE (testreg) == PARALLEL
&& GET_MODE (testreg) == BLKmode)
|| GET_CODE (testreg) == REG)
{
count_reg_references (SET_SRC (x));
if (mark_dest)
count_reg_references (SET_DEST (x));
return;
}
}
break;
default:
break;
}
{
register char *fmt = GET_RTX_FORMAT (code);
register int i;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
if (i == 0)
{
x = XEXP (x, 0);
goto retry;
}
count_reg_references (XEXP (x, i));
}
else if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (x, i); j++)
count_reg_references (XVECEXP (x, i, j));
}
}
}
}
void
recompute_reg_usage (f, loop_step)
rtx f;
int loop_step;
{
rtx insn;
int i, max_reg;
max_reg = max_reg_num ();
for (i = FIRST_PSEUDO_REGISTER; i < max_reg; i++)
{
REG_N_SETS (i) = 0;
REG_N_REFS (i) = 0;
}
loop_depth = 1;
for (insn = f; insn; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) == NOTE)
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
loop_depth -= loop_step;
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
loop_depth += loop_step;
if (loop_depth == 0)
abort ();
}
else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
rtx links;
count_reg_sets (PATTERN (insn));
for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
{
if (REG_NOTE_KIND (links) == REG_INC)
REG_N_SETS (REGNO (XEXP (links, 0)))++;
}
count_reg_references (PATTERN (insn));
if (GET_CODE (insn) == CALL_INSN)
{
rtx note;
for (note = CALL_INSN_FUNCTION_USAGE (insn);
note;
note = XEXP (note, 1))
if (GET_CODE (XEXP (note, 0)) == USE)
count_reg_references (SET_DEST (XEXP (note, 0)));
}
}
}
}
void
set_block_for_insn (insn, bb)
rtx insn;
basic_block bb;
{
size_t uid = INSN_UID (insn);
if (uid >= basic_block_for_insn->num_elements)
{
int new_size;
new_size = uid + (uid + 7) / 8;
VARRAY_GROW (basic_block_for_insn, new_size);
}
VARRAY_BB (basic_block_for_insn, uid) = bb;
}
void
set_block_num (insn, bb)
rtx insn;
int bb;
{
set_block_for_insn (insn, BASIC_BLOCK (bb));
}
void
verify_flow_info ()
{
const int max_uid = get_max_uid ();
const rtx rtx_first = get_insns ();
basic_block *bb_info;
rtx x;
int i;
bb_info = (basic_block *) alloca (max_uid * sizeof (basic_block));
memset (bb_info, 0, max_uid * sizeof (basic_block));
for (i = n_basic_blocks - 1; i >= 0; i--)
{
basic_block bb = BASIC_BLOCK (i);
for (x = rtx_first; x != NULL_RTX; x = NEXT_INSN (x))
if (x == bb->head)
break;
if (!x)
{
fatal ("verify_flow_info: Head insn %d for block %d not found in the insn stream.\n",
INSN_UID (bb->head), bb->index);
}
for (x = bb->head; x != NULL_RTX; x = NEXT_INSN (x))
{
if (bb_info[INSN_UID (x)] != NULL)
{
fatal ("verify_flow_info: Insn %d is in multiple basic blocks (%d and %d)",
INSN_UID (x), bb->index, bb_info[INSN_UID (x)]->index);
}
bb_info[INSN_UID (x)] = bb;
if (x == bb->end)
break;
}
if (!x)
{
fatal ("verify_flow_info: End insn %d for block %d not found in the insn stream.\n",
INSN_UID (bb->end), bb->index);
}
}
for (i = n_basic_blocks - 1; i >= 0; i--)
{
basic_block bb = BASIC_BLOCK (i);
edge e;
e = bb->succ;
while (e)
{
if (e->src != bb)
{
fprintf (stderr, "verify_flow_info: Basic block %d succ edge is corrupted\n",
bb->index);
fprintf (stderr, "Predecessor: ");
dump_edge_info (stderr, e, 0);
fprintf (stderr, "\nSuccessor: ");
dump_edge_info (stderr, e, 1);
fflush (stderr);
abort ();
}
if (e->dest != EXIT_BLOCK_PTR)
{
edge e2 = e->dest->pred;
while (e2 && e2 != e)
e2 = e2->pred_next;
if (!e2)
{
fatal ("verify_flow_info: Basic block %i edge lists are corrupted\n",
bb->index);
}
}
e = e->succ_next;
}
e = bb->pred;
while (e)
{
if (e->dest != bb)
{
fprintf (stderr, "verify_flow_info: Basic block %d pred edge is corrupted\n",
bb->index);
fprintf (stderr, "Predecessor: ");
dump_edge_info (stderr, e, 0);
fprintf (stderr, "\nSuccessor: ");
dump_edge_info (stderr, e, 1);
fflush (stderr);
abort ();
}
if (e->src != ENTRY_BLOCK_PTR)
{
edge e2 = e->src->succ;
while (e2 && e2 != e)
e2 = e2->succ_next;
if (!e2)
{
fatal ("verify_flow_info: Basic block %i edge lists are corrupted\n",
bb->index);
}
}
e = e->pred_next;
}
x = bb->head;
if (GET_CODE (x) == CODE_LABEL)
{
if (bb->end == x)
{
fatal ("verify_flow_info: Basic block contains only CODE_LABEL and no NOTE_INSN_BASIC_BLOCK note\n");
}
x = NEXT_INSN (x);
}
if (GET_CODE (x) != NOTE
|| NOTE_LINE_NUMBER (x) != NOTE_INSN_BASIC_BLOCK
|| NOTE_BASIC_BLOCK (x) != bb)
{
fatal ("verify_flow_info: NOTE_INSN_BASIC_BLOCK is missing for block %d\n",
bb->index);
}
if (bb->end == x)
{
}
else
{
x = NEXT_INSN (x);
while (x)
{
if (GET_CODE (x) == NOTE
&& NOTE_LINE_NUMBER (x) == NOTE_INSN_BASIC_BLOCK)
{
fatal ("verify_flow_info: NOTE_INSN_BASIC_BLOCK %d in the middle of basic block %d\n",
INSN_UID (x), bb->index);
}
if (x == bb->end)
break;
if (GET_CODE (x) == JUMP_INSN
|| GET_CODE (x) == CODE_LABEL
|| GET_CODE (x) == BARRIER)
{
fatal_insn ("verify_flow_info: Incorrect insn in the middle of basic block %d\n",
x, bb->index);
}
x = NEXT_INSN (x);
}
}
}
x = rtx_first;
while (x)
{
if (!bb_info[INSN_UID (x)])
{
switch (GET_CODE (x))
{
case BARRIER:
case NOTE:
break;
case CODE_LABEL:
if (NEXT_INSN (x)
&& GET_CODE (NEXT_INSN (x)) == JUMP_INSN
&& (GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_DIFF_VEC
|| GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_VEC))
{
x = NEXT_INSN (x);
}
break;
default:
fatal_insn ("verify_flow_info: Insn outside basic block\n", x);
}
}
x = NEXT_INSN (x);
}
}