Commit 5c35539b by Richard Henderson Committed by Richard Henderson

flow.c (find_basic_blocks): Calc upper bound for extra nops in max_uids_for_flow.

        * flow.c (find_basic_blocks): Calc upper bound for extra nops in
        max_uids_for_flow.
        (find_basic_blocks_1): Add a nop to the end of a basic block when
        a trailing call insn does not have abnormal control flow.
        * gcse.c (pre_transpout): New variable.
        (alloc_pre_mem, free_pre_mem, dump_pre_data): Bookkeeping for it.
        (compute_pre_transpout): Calculate it.
        (compute_pre_ppinout): Use it to eliminate impossible placements
        due to abnormal control flow through calls.
        (compute_pre_data): Call compute_pre_transpout.

From-SVN: r22907
parent 58d9f9d9
Thu Oct 8 01:25:22 1998 Richard Henderson <rth@cygnus.com>
* flow.c (find_basic_blocks): Calc upper bound for extra nops in
max_uids_for_flow.
(find_basic_blocks_1): Add a nop to the end of a basic block when
a trailing call insn does not have abnormal control flow.
* gcse.c (pre_transpout): New variable.
(alloc_pre_mem, free_pre_mem, dump_pre_data): Bookkeeping for it.
(compute_pre_transpout): Calculate it.
(compute_pre_ppinout): Use it to eliminate impossible placements
due to abnormal control flow through calls.
(compute_pre_data): Call compute_pre_transpout.
Wed Oct 7 21:40:24 1998 David S. Miller <davem@pierdol.cobaltmicro.com>
* config/sparc/sol2-sld-64.h (ASM_CPU_SPEC): Fix typo.
......
......@@ -306,6 +306,7 @@ find_basic_blocks (f, nregs, file, live_reachable_p)
register int i;
rtx nonlocal_label_list = nonlocal_label_rtx_list ();
int in_libcall_block = 0;
int extra_uids_for_flow = 0;
/* Count the basic blocks. Also find maximum insn uid value used. */
......@@ -318,7 +319,6 @@ find_basic_blocks (f, nregs, file, live_reachable_p)
for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
{
/* Track when we are inside in LIBCALL block. */
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& find_reg_note (insn, REG_LIBCALL, NULL_RTX))
......@@ -327,13 +327,33 @@ find_basic_blocks (f, nregs, file, live_reachable_p)
code = GET_CODE (insn);
if (INSN_UID (insn) > max_uid_for_flow)
max_uid_for_flow = INSN_UID (insn);
if (code == CODE_LABEL
|| (GET_RTX_CLASS (code) == 'i'
&& (prev_code == JUMP_INSN
|| (prev_code == CALL_INSN
&& (nonlocal_label_list != 0 || eh_region))
|| prev_code == BARRIER)))
if (code == CODE_LABEL)
i++;
else if (GET_RTX_CLASS (code) == 'i')
{
if (prev_code == JUMP_INSN || prev_code == BARRIER)
i++;
else if (prev_code == CALL_INSN)
{
if (nonlocal_label_list != 0 || eh_region)
i++;
else
{
/* Else this call does not force a new block to be
created. However, it may still be the end of a basic
block if it is followed by a CODE_LABEL or a BARRIER.
To disambiguate calls which force new blocks to be
created from those which just happen to be at the end
of a block we insert nops during find_basic_blocks_1
after calls which are the last insn in a block by
chance. We must account for such insns in
max_uid_for_flow. */
extra_uids_for_flow++;
}
}
}
/* We change the code of the CALL_INSN, so that it won't start a
new block. */
......@@ -360,6 +380,7 @@ find_basic_blocks (f, nregs, file, live_reachable_p)
These cases are rare, so we don't need too much space. */
max_uid_for_flow += max_uid_for_flow / 10;
#endif
max_uid_for_flow += extra_uids_for_flow;
/* Allocate some tables that last till end of compiling this function
and some needed only in find_basic_blocks and life_analysis. */
......@@ -410,6 +431,7 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
int depth, pass;
int in_libcall_block = 0;
int deleted_handler = 0;
int call_had_abnormal_edge = 0;
pass = 1;
active_eh_region = (int *) alloca ((max_uid_for_flow + 1) * sizeof (int));
......@@ -456,8 +478,7 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
else if (code == CODE_LABEL
|| (GET_RTX_CLASS (code) == 'i'
&& (prev_code == JUMP_INSN
|| (prev_code == CALL_INSN
&& (nonlocal_label_list != 0 || eh_note))
|| (prev_code == CALL_INSN && call_had_abnormal_edge)
|| prev_code == BARRIER)))
{
basic_block_head[++i] = insn;
......@@ -466,12 +487,26 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
if (code == CODE_LABEL)
{
LABEL_REFS (insn) = insn;
/* Any label that cannot be deleted
is considered to start a reachable block. */
if (LABEL_PRESERVE_P (insn))
block_live[i] = 1;
}
LABEL_REFS (insn) = insn;
/* Any label that cannot be deleted
is considered to start a reachable block. */
if (LABEL_PRESERVE_P (insn))
block_live[i] = 1;
}
/* If the previous insn was a call that did not create an
abnormal edge, we want to add a nop so that the CALL_INSN
itself is not at basic_block_end. This allows us to easily
distinguish between normal calls and those which create
abnormal edges in the flow graph. */
if (i > 0 && !call_had_abnormal_edge
&& GET_CODE (basic_block_end[i-1]) == CALL_INSN)
{
rtx nop = gen_rtx_USE (VOIDmode, const0_rtx);
nop = emit_insn_after (nop, basic_block_end[i-1]);
basic_block_end[i-1] = nop;
}
}
else if (GET_RTX_CLASS (code) == 'i')
......@@ -524,6 +559,10 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
if (code == CALL_INSN && in_libcall_block)
code = INSN;
/* Record whether this call created an edge. */
if (code == CALL_INSN)
call_had_abnormal_edge = (nonlocal_label_list != 0 || eh_note);
if (code != NOTE)
prev_code = code;
......
......@@ -3888,6 +3888,11 @@ static sbitmap *pre_pavout;
static sbitmap *pre_ppin;
static sbitmap *pre_ppout;
/* Nonzero for expressions that are transparent at the end of the block.
This is only zero for expressions killed by abnormal critical edge
created by a calls. */
static sbitmap *pre_transpout;
/* Used while performing PRE to denote which insns are redundant. */
static sbitmap pre_redundant;
......@@ -3910,6 +3915,8 @@ alloc_pre_mem (n_blocks, n_exprs)
pre_pavout = sbitmap_vector_alloc (n_blocks, n_exprs);
pre_ppin = sbitmap_vector_alloc (n_blocks, n_exprs);
pre_ppout = sbitmap_vector_alloc (n_blocks, n_exprs);
pre_transpout = sbitmap_vector_alloc (n_blocks, n_exprs);
}
/* Free vars used for PRE analysis. */
......@@ -3920,7 +3927,6 @@ free_pre_mem ()
free (pre_transp);
free (pre_comp);
free (pre_antloc);
free (pre_avin);
free (pre_avout);
free (pre_antin);
......@@ -3930,6 +3936,7 @@ free_pre_mem ()
free (pre_pavout);
free (pre_ppin);
free (pre_ppout);
free (pre_transpout);
}
/* Dump PRE data. */
......@@ -3962,6 +3969,9 @@ dump_pre_data (file)
pre_ppin, n_basic_blocks);
dump_sbitmap_vector (file, "PRE placement possible on outgoing", "BB",
pre_ppout, n_basic_blocks);
dump_sbitmap_vector (file, "PRE transparent on outgoing", "BB",
pre_transpout, n_basic_blocks);
}
/* Compute the local properties of each recorded expression.
......@@ -4129,6 +4139,57 @@ compute_pre_pavinout ()
fprintf (gcse_file, "partially avail expr computation: %d passes\n", passes);
}
/* Compute transparent outgoing information for each block.
An expression is transparent to an edge unless it is killed by
the edge itself. This can only happen with abnormal control flow,
when the edge is traversed through a call. This happens with
non-local labels and exceptions.
This would not be necessary if we split the edge. While this is
normally impossible for abnormal critical edges, with some effort
it should be possible with exception handling, since we still have
control over which handler should be invoked. But due to increased
EH table sizes, this may not be worthwhile. */
static void
compute_pre_transpout ()
{
int bb;
sbitmap_vector_ones (pre_transpout, n_basic_blocks);
for (bb = 0; bb < n_basic_blocks; ++bb)
{
int i;
/* Note that flow inserted a nop a the end of basic blocks that
end in call instructions for reasons other than abnormal
control flow. */
if (GET_CODE (BLOCK_END (bb)) != CALL_INSN)
continue;
for (i = 0; i < expr_hash_table_size; i++)
{
struct expr *expr;
for (expr = expr_hash_table[i]; expr ; expr = expr->next_same_hash)
if (GET_CODE (expr->expr) == MEM)
{
rtx addr = XEXP (expr->expr, 0);
if (GET_CODE (addr) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (addr))
continue;
/* ??? Optimally, we would use interprocedural alias
analysis to determine if this mem is actually killed
by this call. */
RESET_BIT (pre_transpout[bb], expr->bitmap_index);
}
}
}
}
/* Compute "placement possible" information on entrance and exit of
each block.
......@@ -4209,11 +4270,12 @@ compute_pre_ppinout ()
for (bb = 0; bb < n_basic_blocks - 1; bb++)
{
sbitmap_ptr ppout = pre_ppout[bb]->elms;
sbitmap_ptr transpout = pre_transpout[bb]->elms;
for (i = 0; i < size; i++)
{
int_list_ptr succ;
SBITMAP_ELT_TYPE tmp = -1L;
SBITMAP_ELT_TYPE tmp = *transpout;
for (succ = s_succs[bb]; succ != NULL; succ = succ->next)
{
......@@ -4226,13 +4288,14 @@ compute_pre_ppinout ()
ppin = pre_ppin[succ_bb]->elms + i;
tmp &= *ppin;
}
if (*ppout != tmp)
{
changed = 1;
*ppout++ = tmp;
*ppout = tmp;
}
else
ppout++;
ppout++; transpout++;
}
}
......@@ -4252,6 +4315,7 @@ compute_pre_data ()
compute_pre_avinout ();
compute_pre_antinout ();
compute_pre_pavinout ();
compute_pre_transpout ();
compute_pre_ppinout ();
if (gcse_file)
fprintf (gcse_file, "\n");
......@@ -4376,10 +4440,7 @@ pre_insert_insn (expr, bb)
}
/* Likewise if the last insn is a call, as will happen in the presence
of exception handling. */
/* ??? The flag_exceptions test is not exact. We don't know if we are
actually in an eh region. Fix flow to tell us this. */
else if (GET_CODE (insn) == CALL_INSN
&& (current_function_has_nonlocal_label || flag_exceptions))
else if (GET_CODE (insn) == CALL_INSN)
{
HARD_REG_SET parm_regs;
int nparm_regs;
......@@ -4409,7 +4470,7 @@ pre_insert_insn (expr, bb)
{
int regno = REGNO (XEXP (XEXP (p, 0), 0));
if (regno >= FIRST_PSEUDO_REGISTER)
abort();
abort ();
SET_HARD_REG_BIT (parm_regs, regno);
nparm_regs++;
}
......
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