re PR rtl-optimization/33644 (ICE in local_cprop_pass with -ftrapv for crafty)
PR rtl-optimization/33644 * cfgcleanup.c: Do not include dce.h. * cfgrtl.c (delete_insn_chain_and_edges): Resurrect. * combine.c (distribute_notes): Delete REG_LIBCALL_ID case. * dce.c (something_changed): Delete. (libcall_dead_p): New predicate. (delete_unmarked_insns): Use it to delete dead libcalls. Deal with REG_LIBCALL and REG_RETVAL notes. (prescan_libcall_for_dce): New function. (prescan_insns_for_dce): Use it to deal with libcalls. (mark_reg_dependencies): Do nothing special for libcalls. (dce_process_block): Likewise. (fast_dce): Delete unused local variable. (run_fast_dce): Do not return a value. * dce.h (struct df): Delete. (run_fast_dce): Adjust prototype. * optabs.c (libcall_id): Delete. (maybe_encapsulate_block): Do not emit REG_LIBCALL_ID notes. (emit_no_conflict_block): Do not look for REG_LIBCALL_ID notes. * reload1.c (reload): Delete REG_LIBCALL_ID case. * rtl.h (delete_insn_chain_and_edges): Resurrect prototype. * see.c (see_update_relevancy): Look for REG_LIBCALL and REG_RETVAL notes instead of REG_LIBCALL_ID notes. * reg-notes.def (LIBCALL_ID): Delete. * Makefile.in (see.o): Add dce.h dependency. (cfgcleanup.o): Remove dce.h dependency. From-SVN: r129556
This commit is contained in:
parent
6e684eee8d
commit
9ed7b22165
@ -1,3 +1,32 @@
|
||||
2007-10-22 Eric Botcazou <ebotcazou@libertysurf.fr>
|
||||
|
||||
PR rtl-optimization/33644
|
||||
* cfgcleanup.c: Do not include dce.h.
|
||||
* cfgrtl.c (delete_insn_chain_and_edges): Resurrect.
|
||||
* combine.c (distribute_notes): Delete REG_LIBCALL_ID case.
|
||||
* dce.c (something_changed): Delete.
|
||||
(libcall_dead_p): New predicate.
|
||||
(delete_unmarked_insns): Use it to delete dead libcalls.
|
||||
Deal with REG_LIBCALL and REG_RETVAL notes.
|
||||
(prescan_libcall_for_dce): New function.
|
||||
(prescan_insns_for_dce): Use it to deal with libcalls.
|
||||
(mark_reg_dependencies): Do nothing special for libcalls.
|
||||
(dce_process_block): Likewise.
|
||||
(fast_dce): Delete unused local variable.
|
||||
(run_fast_dce): Do not return a value.
|
||||
* dce.h (struct df): Delete.
|
||||
(run_fast_dce): Adjust prototype.
|
||||
* optabs.c (libcall_id): Delete.
|
||||
(maybe_encapsulate_block): Do not emit REG_LIBCALL_ID notes.
|
||||
(emit_no_conflict_block): Do not look for REG_LIBCALL_ID notes.
|
||||
* reload1.c (reload): Delete REG_LIBCALL_ID case.
|
||||
* rtl.h (delete_insn_chain_and_edges): Resurrect prototype.
|
||||
* see.c (see_update_relevancy): Look for REG_LIBCALL and REG_RETVAL
|
||||
notes instead of REG_LIBCALL_ID notes.
|
||||
* reg-notes.def (LIBCALL_ID): Delete.
|
||||
* Makefile.in (see.o): Add dce.h dependency.
|
||||
(cfgcleanup.o): Remove dce.h dependency.
|
||||
|
||||
2007-10-22 Michael Matz <matz@suse.de>
|
||||
|
||||
PR tree-optimization/33855
|
||||
|
@ -2543,7 +2543,7 @@ web.o : web.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||
$(DF_H) $(OBSTACK_H) $(TIMEVAR_H) tree-pass.h
|
||||
see.o : see.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||
hard-reg-set.h $(FLAGS_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h toplev.h \
|
||||
$(DF_H) $(OBSTACK_H) $(TIMEVAR_H) tree-pass.h $(EXPR_H)
|
||||
$(DF_H) $(OBSTACK_H) $(TIMEVAR_H) tree-pass.h $(EXPR_H) dce.h
|
||||
gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||
$(REGS_H) hard-reg-set.h $(FLAGS_H) $(REAL_H) insn-config.h $(GGC_H) \
|
||||
$(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h toplev.h \
|
||||
@ -2648,7 +2648,7 @@ cfgcleanup.o : cfgcleanup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
|
||||
$(RTL_H) $(TIMEVAR_H) hard-reg-set.h output.h $(FLAGS_H) $(RECOG_H) \
|
||||
toplev.h insn-config.h cselib.h $(TARGET_H) $(TM_P_H) $(PARAMS_H) \
|
||||
$(REGS_H) $(EMIT_RTL_H) $(CFGLAYOUT_H) tree-pass.h $(CFGLOOP_H) $(EXPR_H) \
|
||||
$(DF_H) dce.h
|
||||
$(DF_H)
|
||||
cfgloop.o : cfgloop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) coretypes.h $(TM_H) \
|
||||
$(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(FLAGS_H) $(FUNCTION_H) \
|
||||
$(OBSTACK_H) toplev.h $(TREE_FLOW_H) $(TREE_H) pointer-set.h output.h \
|
||||
|
@ -54,7 +54,6 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "cfgloop.h"
|
||||
#include "expr.h"
|
||||
#include "df.h"
|
||||
#include "dce.h"
|
||||
|
||||
#define FORWARDER_BLOCK_P(BB) ((BB)->flags & BB_FORWARDER_BLOCK)
|
||||
|
||||
|
17
gcc/cfgrtl.c
17
gcc/cfgrtl.c
@ -187,6 +187,7 @@ delete_insn (rtx insn)
|
||||
}
|
||||
|
||||
/* Like delete_insn but also purge dead edges from BB. */
|
||||
|
||||
rtx
|
||||
delete_insn_and_edges (rtx insn)
|
||||
{
|
||||
@ -231,6 +232,22 @@ delete_insn_chain (rtx start, rtx finish, bool clear_bb)
|
||||
start = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Like delete_insn_chain but also purge dead edges from BB. */
|
||||
|
||||
void
|
||||
delete_insn_chain_and_edges (rtx first, rtx last)
|
||||
{
|
||||
bool purge = false;
|
||||
|
||||
if (INSN_P (last)
|
||||
&& BLOCK_FOR_INSN (last)
|
||||
&& BB_END (BLOCK_FOR_INSN (last)) == last)
|
||||
purge = true;
|
||||
delete_insn_chain (first, last, false);
|
||||
if (purge)
|
||||
purge_dead_edges (BLOCK_FOR_INSN (last));
|
||||
}
|
||||
|
||||
/* Create a new basic block consisting of the instructions between HEAD and END
|
||||
inclusive. This function is designed to allow fast BB construction - reuses
|
||||
|
@ -12509,15 +12509,6 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
|
||||
to simply delete it. */
|
||||
break;
|
||||
|
||||
case REG_LIBCALL_ID:
|
||||
/* If the insn previously containing this note still exists,
|
||||
put it back where it was. Otherwise move it to the previous
|
||||
insn. */
|
||||
if (!NOTE_P (from_insn))
|
||||
place = from_insn;
|
||||
else
|
||||
place = prev_real_insn (from_insn);
|
||||
break;
|
||||
case REG_RETVAL:
|
||||
/* If the insn previously containing this note still exists,
|
||||
put it back where it was. Otherwise move it to the previous
|
||||
|
309
gcc/dce.c
309
gcc/dce.c
@ -46,9 +46,6 @@ DEF_VEC_ALLOC_I(int,heap);
|
||||
we don't want to reenter it. */
|
||||
static bool df_in_progress = false;
|
||||
|
||||
/* True if we deleted at least one instruction. */
|
||||
static bool something_changed;
|
||||
|
||||
/* Instructions that have been marked but whose dependencies have not
|
||||
yet been processed. */
|
||||
static VEC(rtx,heap) *worklist;
|
||||
@ -203,6 +200,62 @@ mark_nonreg_stores (rtx body, rtx insn, bool fast)
|
||||
}
|
||||
|
||||
|
||||
/* Return true if the entire libcall sequence starting at INSN is dead.
|
||||
NOTE is the REG_LIBCALL note attached to INSN.
|
||||
|
||||
A libcall sequence is a block of insns with no side-effects, i.e.
|
||||
that is only used for its return value. The terminology derives
|
||||
from that of a call, but a libcall sequence need not contain one.
|
||||
It is only defined by a pair of REG_LIBCALL/REG_RETVAL notes.
|
||||
|
||||
From a dataflow viewpoint, a libcall sequence has the property that
|
||||
no UD chain can enter it from the outside. As a consequence, if a
|
||||
libcall sequence has a dead return value, it is effectively dead.
|
||||
This is both enforced by CSE (cse_extended_basic_block) and relied
|
||||
upon by delete_trivially_dead_insns.
|
||||
|
||||
However, in practice, the return value business is a tricky one and
|
||||
only checking the liveness of the last insn is not sufficient to
|
||||
decide whether the whole sequence is dead (e.g. PR middle-end/19551)
|
||||
so we check the liveness of every insn starting from the call. */
|
||||
|
||||
static bool
|
||||
libcall_dead_p (rtx insn, rtx note)
|
||||
{
|
||||
rtx last = XEXP (note, 0);
|
||||
|
||||
/* Find the call insn. */
|
||||
while (insn != last && !CALL_P (insn))
|
||||
insn = NEXT_INSN (insn);
|
||||
|
||||
/* If there is none, do nothing special, since ordinary death handling
|
||||
can understand these insns. */
|
||||
if (!CALL_P (insn))
|
||||
return false;
|
||||
|
||||
/* If this is a call that returns a value via an invisible pointer, the
|
||||
dataflow engine cannot see it so it has been marked unconditionally.
|
||||
Skip it unless it has been made the last insn in the libcall, for
|
||||
example by the combiner, in which case we're left with no easy way
|
||||
of asserting its liveness. */
|
||||
if (!single_set (insn))
|
||||
{
|
||||
if (insn == last)
|
||||
return false;
|
||||
insn = NEXT_INSN (insn);
|
||||
}
|
||||
|
||||
while (insn != NEXT_INSN (last))
|
||||
{
|
||||
if (INSN_P (insn) && marked_insn_p (insn))
|
||||
return false;
|
||||
insn = NEXT_INSN (insn);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Delete all REG_EQUAL notes of the registers INSN writes, to prevent
|
||||
bad dangling REG_EQUAL notes. */
|
||||
|
||||
@ -236,8 +289,7 @@ delete_corresponding_reg_eq_notes (rtx insn)
|
||||
}
|
||||
|
||||
|
||||
/* Delete every instruction that hasn't been marked. Clear the insn
|
||||
from DCE_DF if DF_DELETE is true. */
|
||||
/* Delete every instruction that hasn't been marked. */
|
||||
|
||||
static void
|
||||
delete_unmarked_insns (void)
|
||||
@ -245,107 +297,115 @@ delete_unmarked_insns (void)
|
||||
basic_block bb;
|
||||
rtx insn, next;
|
||||
|
||||
something_changed = false;
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
FOR_BB_INSNS_SAFE (bb, insn, next)
|
||||
if (INSN_P (insn))
|
||||
{
|
||||
rtx note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
|
||||
|
||||
/* Always delete no-op moves. */
|
||||
if (noop_move_p (insn))
|
||||
;
|
||||
|
||||
/* Try to delete libcall sequences as a whole. */
|
||||
else if (note && libcall_dead_p (insn, note))
|
||||
{
|
||||
/* Note that this code does not handle the case where
|
||||
the last insn of libcall is deleted. As it turns out
|
||||
this case is excluded in the call to noop_move_p. */
|
||||
rtx note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
|
||||
if (note && (XEXP (note, 0) != insn))
|
||||
{
|
||||
rtx new_libcall_insn = next_real_insn (insn);
|
||||
rtx retval_note = find_reg_note (XEXP (note, 0),
|
||||
REG_RETVAL, NULL_RTX);
|
||||
REG_NOTES (new_libcall_insn)
|
||||
= gen_rtx_INSN_LIST (REG_LIBCALL, XEXP (note, 0),
|
||||
REG_NOTES (new_libcall_insn));
|
||||
XEXP (retval_note, 0) = new_libcall_insn;
|
||||
}
|
||||
rtx last = XEXP (note, 0);
|
||||
|
||||
if (!dbg_cnt (dce))
|
||||
continue;
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "DCE: Deleting libcall %d-%d\n",
|
||||
INSN_UID (insn), INSN_UID (last));
|
||||
|
||||
next = NEXT_INSN (last);
|
||||
delete_insn_chain_and_edges (insn, last);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Otherwise rely only on the DCE algorithm. */
|
||||
else if (marked_insn_p (insn))
|
||||
continue;
|
||||
|
||||
/* WARNING, this debugging can itself cause problems if the
|
||||
edge of the counter causes part of a libcall to be
|
||||
deleted but not all of it. */
|
||||
if (!dbg_cnt (dce))
|
||||
continue;
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "DCE: Deleting insn %d\n", INSN_UID (insn));
|
||||
|
||||
/* Before we delete the insn, we have to delete
|
||||
REG_EQUAL of the destination regs of the deleted insn
|
||||
to prevent dangling REG_EQUAL. */
|
||||
delete_corresponding_reg_eq_notes (insn);
|
||||
/* Before we delete the insn we have to delete REG_EQUAL notes
|
||||
for the destination regs in order to avoid dangling notes. */
|
||||
delete_corresponding_reg_eq_notes (insn);
|
||||
|
||||
/* If we're about to delete the first insn of a libcall, then
|
||||
move the REG_LIBCALL note to the next real insn and update
|
||||
the REG_RETVAL note. */
|
||||
if (note && (XEXP (note, 0) != insn))
|
||||
{
|
||||
rtx new_libcall_insn = next_real_insn (insn);
|
||||
rtx retval_note = find_reg_note (XEXP (note, 0),
|
||||
REG_RETVAL, NULL_RTX);
|
||||
REG_NOTES (new_libcall_insn)
|
||||
= gen_rtx_INSN_LIST (REG_LIBCALL, XEXP (note, 0),
|
||||
REG_NOTES (new_libcall_insn));
|
||||
XEXP (retval_note, 0) = new_libcall_insn;
|
||||
}
|
||||
|
||||
/* If the insn contains a REG_RETVAL note and is dead, but the
|
||||
libcall as a whole is not dead, then we want to remove the
|
||||
insn, but not the whole libcall sequence. However, we also
|
||||
need to remove the dangling REG_LIBCALL note in order to
|
||||
avoid mismatched notes. We could find a new location for
|
||||
the REG_RETVAL note, but it hardly seems worth the effort. */
|
||||
note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
|
||||
if (note && (XEXP (note, 0) != insn))
|
||||
{
|
||||
rtx libcall_note
|
||||
= find_reg_note (XEXP (note, 0), REG_LIBCALL, NULL_RTX);
|
||||
remove_note (XEXP (note, 0), libcall_note);
|
||||
}
|
||||
|
||||
/* Now delete the insn. */
|
||||
delete_insn_and_edges (insn);
|
||||
something_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Mark all insns using DELETE_PARM in the libcall that contains
|
||||
START_INSN. */
|
||||
/* Helper function for prescan_insns_for_dce: prescan the entire libcall
|
||||
sequence starting at INSN and return the insn following the libcall.
|
||||
NOTE is the REG_LIBCALL note attached to INSN. */
|
||||
|
||||
static void
|
||||
mark_libcall (rtx start_insn, bool delete_parm)
|
||||
static rtx
|
||||
prescan_libcall_for_dce (rtx insn, rtx note, bool fast)
|
||||
{
|
||||
rtx note = find_reg_note (start_insn, REG_LIBCALL_ID, NULL_RTX);
|
||||
int id = INTVAL (XEXP (note, 0));
|
||||
rtx insn;
|
||||
rtx last = XEXP (note, 0);
|
||||
|
||||
mark_insn (start_insn, delete_parm);
|
||||
insn = NEXT_INSN (start_insn);
|
||||
|
||||
/* There are tales, long ago and far away, of the mystical nested
|
||||
libcall. No one alive has actually seen one, but other parts of
|
||||
the compiler support them so we will here. */
|
||||
for (insn = NEXT_INSN (start_insn); insn; insn = NEXT_INSN (insn))
|
||||
/* A libcall is never necessary on its own but we need to mark the stores
|
||||
to a non-register destination. */
|
||||
while (insn != last && !CALL_P (insn))
|
||||
{
|
||||
if (INSN_P (insn))
|
||||
{
|
||||
/* Stay in the loop as long as we are in any libcall. */
|
||||
if ((note = find_reg_note (insn, REG_LIBCALL_ID, NULL_RTX)))
|
||||
{
|
||||
if (id == INTVAL (XEXP (note, 0)))
|
||||
{
|
||||
mark_insn (insn, delete_parm);
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "matching forward libcall %d[%d]\n",
|
||||
INSN_UID (insn), id);
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
mark_nonreg_stores (PATTERN (insn), insn, fast);
|
||||
insn = NEXT_INSN (insn);
|
||||
}
|
||||
|
||||
for (insn = PREV_INSN (start_insn); insn; insn = PREV_INSN (insn))
|
||||
|
||||
/* If this is a call that returns a value via an invisible pointer, the
|
||||
dataflow engine cannot see it so it has to be marked unconditionally. */
|
||||
if (CALL_P (insn) && !single_set (insn))
|
||||
{
|
||||
mark_insn (insn, fast);
|
||||
insn = NEXT_INSN (insn);
|
||||
}
|
||||
|
||||
while (insn != NEXT_INSN (last))
|
||||
{
|
||||
if (INSN_P (insn))
|
||||
{
|
||||
/* Stay in the loop as long as we are in any libcall. */
|
||||
if ((note = find_reg_note (insn, REG_LIBCALL_ID, NULL_RTX)))
|
||||
{
|
||||
if (id == INTVAL (XEXP (note, 0)))
|
||||
{
|
||||
mark_insn (insn, delete_parm);
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "matching backward libcall %d[%d]\n",
|
||||
INSN_UID (insn), id);
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
mark_nonreg_stores (PATTERN (insn), insn, fast);
|
||||
insn = NEXT_INSN (insn);
|
||||
}
|
||||
|
||||
return insn;
|
||||
}
|
||||
|
||||
|
||||
@ -357,23 +417,23 @@ static void
|
||||
prescan_insns_for_dce (bool fast)
|
||||
{
|
||||
basic_block bb;
|
||||
rtx insn;
|
||||
rtx insn, next;
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Finding needed instructions:\n");
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
FOR_BB_INSNS (bb, insn)
|
||||
if (INSN_P (insn))
|
||||
{
|
||||
rtx note = find_reg_note (insn, REG_LIBCALL_ID, NULL_RTX);
|
||||
if (note)
|
||||
mark_libcall (insn, fast);
|
||||
else if (deletable_insn_p (insn, fast))
|
||||
mark_nonreg_stores (PATTERN (insn), insn, fast);
|
||||
else
|
||||
mark_insn (insn, fast);
|
||||
}
|
||||
FOR_BB_INSNS_SAFE (bb, insn, next)
|
||||
if (INSN_P (insn))
|
||||
{
|
||||
rtx note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
|
||||
if (note)
|
||||
next = prescan_libcall_for_dce (insn, note, fast);
|
||||
else if (deletable_insn_p (insn, fast))
|
||||
mark_nonreg_stores (PATTERN (insn), insn, fast);
|
||||
else
|
||||
mark_insn (insn, fast);
|
||||
}
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Finished finding needed instructions:\n");
|
||||
@ -410,10 +470,6 @@ mark_reg_dependencies (rtx insn)
|
||||
struct df_link *defs;
|
||||
struct df_ref **use_rec;
|
||||
|
||||
/* If this is part of a libcall, mark the entire libcall. */
|
||||
if (find_reg_note (insn, REG_LIBCALL_ID, NULL_RTX))
|
||||
mark_libcall (insn, false);
|
||||
|
||||
for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
|
||||
{
|
||||
struct df_ref *use = *use_rec;
|
||||
@ -588,42 +644,19 @@ dce_process_block (basic_block bb, bool redo_out)
|
||||
FOR_BB_INSNS_REVERSE (bb, insn)
|
||||
if (INSN_P (insn))
|
||||
{
|
||||
/* If this is a recursive call, the libcall will have already
|
||||
been marked. */
|
||||
if (!marked_insn_p (insn))
|
||||
{
|
||||
bool needed = false;
|
||||
bool needed = false;
|
||||
|
||||
/* The insn is needed if there is someone who uses the output. */
|
||||
for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
|
||||
if (bitmap_bit_p (local_live, DF_REF_REGNO (*def_rec))
|
||||
|| bitmap_bit_p (au, DF_REF_REGNO (*def_rec)))
|
||||
{
|
||||
needed = true;
|
||||
break;
|
||||
}
|
||||
/* The insn is needed if there is someone who uses the output. */
|
||||
for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
|
||||
if (bitmap_bit_p (local_live, DF_REF_REGNO (*def_rec))
|
||||
|| bitmap_bit_p (au, DF_REF_REGNO (*def_rec)))
|
||||
{
|
||||
needed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (needed)
|
||||
{
|
||||
rtx note = find_reg_note (insn, REG_LIBCALL_ID, NULL_RTX);
|
||||
|
||||
/* If we need to mark an insn in the middle of a
|
||||
libcall, we need to back up to mark the entire
|
||||
libcall. Given that libcalls are rare, rescanning
|
||||
the block should be a reasonable solution to trying
|
||||
to figure out how to back up. */
|
||||
if (note)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "needed libcall %d\n", INSN_UID (insn));
|
||||
mark_libcall (insn, true);
|
||||
BITMAP_FREE (local_live);
|
||||
return dce_process_block (bb, false);
|
||||
}
|
||||
else
|
||||
mark_insn (insn, true);
|
||||
}
|
||||
}
|
||||
if (needed)
|
||||
mark_insn (insn, true);
|
||||
|
||||
/* No matter if the instruction is needed or not, we remove
|
||||
any regno in the defs from the live set. */
|
||||
@ -642,6 +675,7 @@ dce_process_block (basic_block bb, bool redo_out)
|
||||
&& (!(DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL))))
|
||||
bitmap_clear_bit (local_live, DF_REF_REGNO (def));
|
||||
}
|
||||
|
||||
#ifdef EH_USES
|
||||
/* Process the uses that are live into an exception handler. */
|
||||
for (use_rec = df_get_artificial_uses (bb_index); *use_rec; use_rec++)
|
||||
@ -676,7 +710,7 @@ fast_dce (void)
|
||||
bitmap redo_out = BITMAP_ALLOC (&dce_blocks_bitmap_obstack);
|
||||
bitmap all_blocks = BITMAP_ALLOC (&dce_blocks_bitmap_obstack);
|
||||
bool global_changed = true;
|
||||
int i, loop_count = 0;
|
||||
int i;
|
||||
|
||||
prescan_insns_for_dce (true);
|
||||
|
||||
@ -686,6 +720,7 @@ fast_dce (void)
|
||||
while (global_changed)
|
||||
{
|
||||
global_changed = false;
|
||||
|
||||
for (i = 0; i < n_blocks; i++)
|
||||
{
|
||||
int index = postorder[i];
|
||||
@ -739,9 +774,9 @@ fast_dce (void)
|
||||
|
||||
if (old_flag & DF_LR_RUN_DCE)
|
||||
df_set_flags (DF_LR_RUN_DCE);
|
||||
|
||||
prescan_insns_for_dce (true);
|
||||
}
|
||||
loop_count++;
|
||||
}
|
||||
|
||||
delete_unmarked_insns ();
|
||||
@ -793,22 +828,22 @@ run_fast_df_dce (void)
|
||||
}
|
||||
|
||||
|
||||
/* Run a fast DCE pass. */
|
||||
|
||||
void
|
||||
run_fast_dce (void)
|
||||
{
|
||||
if (flag_dce)
|
||||
rest_of_handle_fast_dce ();
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
gate_fast_dce (void)
|
||||
{
|
||||
return optimize > 0 && flag_dce;
|
||||
}
|
||||
|
||||
|
||||
/* Run a fast DCE pass and return true if any instructions were deleted. */
|
||||
|
||||
bool
|
||||
run_fast_dce (void)
|
||||
{
|
||||
return gate_fast_dce () && (rest_of_handle_fast_dce (), something_changed);
|
||||
}
|
||||
|
||||
|
||||
struct tree_opt_pass pass_fast_rtl_dce =
|
||||
{
|
||||
"dce", /* name */
|
||||
|
@ -20,9 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#ifndef GCC_DCE_H
|
||||
#define GCC_DCE_H
|
||||
|
||||
struct df;
|
||||
|
||||
extern bool run_fast_dce (void);
|
||||
extern void run_fast_dce (void);
|
||||
extern void run_fast_df_dce (void);
|
||||
|
||||
#endif /* GCC_DCE_H */
|
||||
|
14
gcc/optabs.c
14
gcc/optabs.c
@ -99,10 +99,6 @@ static void prepare_float_lib_cmp (rtx *, rtx *, enum rtx_code *,
|
||||
enum machine_mode *, int *);
|
||||
static rtx expand_unop_direct (enum machine_mode, optab, rtx, rtx, int);
|
||||
|
||||
/* Current libcall id. It doesn't matter what these are, as long
|
||||
as they are unique to each libcall that is emitted. */
|
||||
static HOST_WIDE_INT libcall_id = 0;
|
||||
|
||||
/* Debug facility for use in GDB. */
|
||||
void debug_optab_libfuncs (void);
|
||||
|
||||
@ -3824,12 +3820,6 @@ maybe_encapsulate_block (rtx first, rtx last, rtx equiv)
|
||||
REG_NOTES (first));
|
||||
REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
|
||||
REG_NOTES (last));
|
||||
next = NEXT_INSN (last);
|
||||
for (insn = first; insn != next; insn = NEXT_INSN (insn))
|
||||
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LIBCALL_ID,
|
||||
GEN_INT (libcall_id),
|
||||
REG_NOTES (insn));
|
||||
libcall_id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3890,8 +3880,6 @@ emit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv)
|
||||
remove_note (insn, note);
|
||||
if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
|
||||
remove_note (insn, note);
|
||||
if ((note = find_reg_note (insn, REG_LIBCALL_ID, NULL)) != NULL)
|
||||
remove_note (insn, note);
|
||||
|
||||
data.target = target;
|
||||
data.first = insns;
|
||||
@ -4044,8 +4032,6 @@ emit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv)
|
||||
remove_note (insn, note);
|
||||
if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
|
||||
remove_note (insn, note);
|
||||
if ((note = find_reg_note (insn, REG_LIBCALL_ID, NULL)) != NULL)
|
||||
remove_note (insn, note);
|
||||
|
||||
next = NEXT_INSN (insn);
|
||||
|
||||
|
@ -163,7 +163,3 @@ REG_NOTE (CROSSING_JUMP)
|
||||
/* This kind of note is generated at each to `setjmp', and similar
|
||||
functions that can return twice. */
|
||||
REG_NOTE (SETJMP)
|
||||
|
||||
/* This kind of note identifies what libcall id an instruction is part of. */
|
||||
REG_NOTE (LIBCALL_ID)
|
||||
|
||||
|
@ -1277,7 +1277,6 @@ reload (rtx first, int global)
|
||||
|| REG_NOTE_KIND (*pnote) == REG_UNUSED
|
||||
|| REG_NOTE_KIND (*pnote) == REG_INC
|
||||
|| REG_NOTE_KIND (*pnote) == REG_RETVAL
|
||||
|| REG_NOTE_KIND (*pnote) == REG_LIBCALL_ID
|
||||
|| REG_NOTE_KIND (*pnote) == REG_LIBCALL)
|
||||
*pnote = XEXP (*pnote, 1);
|
||||
else
|
||||
|
@ -2093,6 +2093,7 @@ extern void emit_insn_at_entry (rtx);
|
||||
extern void delete_insn_chain (rtx, rtx, bool);
|
||||
extern rtx unlink_insn_chain (rtx, rtx);
|
||||
extern rtx delete_insn_and_edges (rtx);
|
||||
extern void delete_insn_chain_and_edges (rtx, rtx);
|
||||
extern rtx gen_lowpart_SUBREG (enum machine_mode, rtx);
|
||||
extern rtx gen_const_mem (enum machine_mode, rtx);
|
||||
extern rtx gen_frame_mem (enum machine_mode, rtx);
|
||||
|
11
gcc/see.c
11
gcc/see.c
@ -3649,9 +3649,9 @@ see_update_defs_relevancy (rtx insn, struct df_ref *ref,
|
||||
|
||||
The information of the u'th use is stored in use_entry[u] and the
|
||||
information of the d'th definition is stored in def_entry[d].
|
||||
|
||||
|
||||
Currently all the uses are relevant for the optimization except for
|
||||
uses that are in LIBCALL instructions. */
|
||||
uses that are in LIBCALL or RETVAL instructions. */
|
||||
|
||||
static void
|
||||
see_update_relevancy (void)
|
||||
@ -3676,13 +3676,12 @@ see_update_relevancy (void)
|
||||
unsigned int uid = INSN_UID (insn);
|
||||
if (INSN_P (insn))
|
||||
{
|
||||
|
||||
/* If this is an insn in a libcall, do not touch the uses. */
|
||||
if (find_reg_note (insn, REG_LIBCALL_ID, NULL_RTX))
|
||||
if (find_reg_note (insn, REG_LIBCALL, NULL_RTX)
|
||||
|| find_reg_note (insn, REG_RETVAL, NULL_RTX))
|
||||
et = NOT_RELEVANT;
|
||||
else
|
||||
et = RELEVANT_USE;
|
||||
|
||||
|
||||
for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
|
||||
{
|
||||
struct df_ref *use = *use_rec;
|
||||
|
@ -1,3 +1,7 @@
|
||||
2007-10-22 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* gcc.dg/pr33644.c: New test.
|
||||
|
||||
2007-10-22 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/33372
|
||||
|
19
gcc/testsuite/gcc.dg/pr33644.c
Normal file
19
gcc/testsuite/gcc.dg/pr33644.c
Normal file
@ -0,0 +1,19 @@
|
||||
/* PR rtl-optimization/33644 */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -ftrapv" } */
|
||||
|
||||
extern char *bar (const char *);
|
||||
|
||||
int *m, *b;
|
||||
|
||||
void foo (void)
|
||||
{
|
||||
int *mv;
|
||||
int p;
|
||||
char a[17];
|
||||
|
||||
p = bar (a) - a;
|
||||
for (mv = m; mv < b; mv++)
|
||||
if (p && ((*mv & 7) != p))
|
||||
*mv=0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user