aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/basic-block.h6
-rw-r--r--gcc/flow.c68
-rw-r--r--gcc/ifcvt.c5
-rw-r--r--gcc/recog.c4
5 files changed, 78 insertions, 19 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6412e06..1d540a9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@
+2000-11-27 Bernd Schmidt <bernds@redhat.co.uk>
+
+ * flow.c (entry_exit_blocks): Add entry for cond_local_set.
+ (struct propagate_block_info): Add new member cond_local_set.
+ (propagate_block): Accept new arg cond_local_set. All callers
+ changed.
+ (init_propagate_block_info): Likewise.
+ (calculate_global_regs_live): Allocate & free cond_local_set. Always
+ rescan if there's overlap between cond_local_set and new_live_at_end.
+ (mark_set_1): Set bits either in cond_local_set or local_set, as
+ appropriate.
+ * basic-block.h (struct basic_block_def): New field cond_local_set.
+ (propagate_block, init_propagate_block_info): Update prototypes.
+
Mon Nov 27 17:29:44 2000 kaz Kojima <kkojima@rr.iij4u.or.jp>
* gcc/config/sh/sh.md (udivsi3_i4, udivsi3_i4_single): Clobber
diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index f3ed1a9..1f6edf1 100644
--- a/gcc/basic-block.h
+++ b/gcc/basic-block.h
@@ -165,6 +165,7 @@ typedef struct basic_block_def {
not reflect the use of regs in phi functions, since the liveness
of these regs may depend on which edge was taken into the block. */
regset local_set;
+ regset cond_local_set;
regset global_live_at_start;
regset global_live_at_end;
@@ -489,12 +490,13 @@ extern void life_analysis PARAMS ((rtx, FILE *, int));
extern void update_life_info PARAMS ((sbitmap, enum update_life_extent,
int));
extern int count_or_remove_death_notes PARAMS ((sbitmap, int));
-extern void propagate_block PARAMS ((basic_block, regset, regset, int));
+extern void propagate_block PARAMS ((basic_block, regset, regset, regset,
+ int));
struct propagate_block_info;
extern rtx propagate_one_insn PARAMS ((struct propagate_block_info *, rtx));
extern struct propagate_block_info *init_propagate_block_info
- PARAMS ((basic_block, regset, regset, int));
+ PARAMS ((basic_block, regset, regset, regset, int));
extern void free_propagate_block_info PARAMS ((struct propagate_block_info *));
/* In lcm.c */
diff --git a/gcc/flow.c b/gcc/flow.c
index 28d23cc..0a20f48 100644
--- a/gcc/flow.c
+++ b/gcc/flow.c
@@ -193,6 +193,7 @@ struct basic_block_def entry_exit_blocks[2]
NULL, /* pred */
NULL, /* succ */
NULL, /* local_set */
+ NULL, /* cond_local_set */
NULL, /* global_live_at_start */
NULL, /* global_live_at_end */
NULL, /* aux */
@@ -207,6 +208,7 @@ struct basic_block_def entry_exit_blocks[2]
NULL, /* pred */
NULL, /* succ */
NULL, /* local_set */
+ NULL, /* cond_local_set */
NULL, /* global_live_at_start */
NULL, /* global_live_at_end */
NULL, /* aux */
@@ -293,9 +295,14 @@ struct propagate_block_info
elimination. */
rtx mem_set_list;
- /* If non-null, record the set of registers set in the basic block. */
+ /* If non-null, record the set of registers set unconditionally in the
+ basic block. */
regset local_set;
+ /* If non-null, record the set of registers set conditionally in the
+ basic block. */
+ regset cond_local_set;
+
#ifdef HAVE_conditional_execution
/* Indexed by register number, holds a reg_cond_life_info for each
register that is not unconditionally live or dead. */
@@ -1544,7 +1551,7 @@ split_block (bb, insn)
at the end of the original basic block and get
propagate_block to determine which registers are live. */
COPY_REG_SET (new_bb->global_live_at_start, bb->global_live_at_end);
- propagate_block (new_bb, new_bb->global_live_at_start, NULL, 0);
+ propagate_block (new_bb, new_bb->global_live_at_start, NULL, NULL, 0);
COPY_REG_SET (bb->global_live_at_end,
new_bb->global_live_at_start);
}
@@ -2966,7 +2973,7 @@ update_life_info (blocks, extent, prop_flags)
basic_block bb = BASIC_BLOCK (i);
COPY_REG_SET (tmp, bb->global_live_at_end);
- propagate_block (bb, tmp, (regset) NULL, prop_flags);
+ propagate_block (bb, tmp, NULL, NULL, prop_flags);
if (extent == UPDATE_LIFE_LOCAL)
verify_local_live_at_start (tmp, bb);
@@ -2979,7 +2986,7 @@ update_life_info (blocks, extent, prop_flags)
basic_block bb = BASIC_BLOCK (i);
COPY_REG_SET (tmp, bb->global_live_at_end);
- propagate_block (bb, tmp, (regset) NULL, prop_flags);
+ propagate_block (bb, tmp, NULL, NULL, prop_flags);
if (extent == UPDATE_LIFE_LOCAL)
verify_local_live_at_start (tmp, bb);
@@ -3378,6 +3385,7 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
if (bb->local_set == NULL)
{
bb->local_set = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+ bb->cond_local_set = OBSTACK_ALLOC_REG_SET (&flow_obstack);
rescan = 1;
}
else
@@ -3392,6 +3400,20 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
if (! rescan)
{
+ /* If any of the registers in the new live_at_end set are
+ conditionally set in this basic block, we must rescan.
+ This is because conditional lifetimes at the end of the
+ block do not just take the live_at_end set into account,
+ but also the liveness at the start of each successor
+ block. We can miss changes in those sets if we only
+ compare the new live_at_end against the previous one. */
+ CLEAR_REG_SET (tmp);
+ rescan = bitmap_operation (tmp, new_live_at_end,
+ bb->cond_local_set, BITMAP_AND);
+ }
+
+ if (! rescan)
+ {
/* Find the set of changed bits. Take this opportunity
to notice that this set is empty and early out. */
CLEAR_REG_SET (tmp);
@@ -3434,7 +3456,8 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
/* Rescan the block insn by insn to turn (a copy of) live_at_end
into live_at_start. */
- propagate_block (bb, new_live_at_end, bb->local_set, flags);
+ propagate_block (bb, new_live_at_end, bb->local_set,
+ bb->cond_local_set, flags);
/* If live_at start didn't change, no need to go farther. */
if (REG_SET_EQUAL_P (bb->global_live_at_start, new_live_at_end))
@@ -3467,6 +3490,7 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
{
basic_block bb = BASIC_BLOCK (i);
FREE_REG_SET (bb->local_set);
+ FREE_REG_SET (bb->cond_local_set);
});
}
else
@@ -3475,6 +3499,7 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
{
basic_block bb = BASIC_BLOCK (i);
FREE_REG_SET (bb->local_set);
+ FREE_REG_SET (bb->cond_local_set);
}
}
@@ -3811,10 +3836,9 @@ propagate_one_insn (pbi, insn)
the user can use the regsets provided here. */
struct propagate_block_info *
-init_propagate_block_info (bb, live, local_set, flags)
+init_propagate_block_info (bb, live, local_set, cond_local_set, flags)
basic_block bb;
- regset live;
- regset local_set;
+ regset live, local_set, cond_local_set;
int flags;
{
struct propagate_block_info *pbi = xmalloc (sizeof (*pbi));
@@ -3823,6 +3847,7 @@ init_propagate_block_info (bb, live, local_set, flags)
pbi->reg_live = live;
pbi->mem_set_list = NULL_RTX;
pbi->local_set = local_set;
+ pbi->cond_local_set = cond_local_set;
pbi->cc0_live = 0;
pbi->flags = flags;
@@ -4000,20 +4025,28 @@ free_propagate_block_info (pbi)
When called, REG_LIVE contains those live at the end. On return, it
contains those live at the beginning.
- LOCAL_SET, if non-null, will be set with all registers killed by
- this basic block. */
+ LOCAL_SET, if non-null, will be set with all registers killed
+ unconditionally by this basic block.
+ Likewise, COND_LOCAL_SET, if non-null, will be set with all registers
+ killed conditionally by this basic block. If there is any unconditional
+ set of a register, then the corresponding bit will be set in LOCAL_SET
+ and cleared in COND_LOCAL_SET.
+ It is valid for LOCAL_SET and COND_LOCAL_SET to be the same set. In this
+ case, the resulting set will be equal to the union of the two sets that
+ would otherwise be computed. */
void
-propagate_block (bb, live, local_set, flags)
+propagate_block (bb, live, local_set, cond_local_set, flags)
basic_block bb;
regset live;
regset local_set;
+ regset cond_local_set;
int flags;
{
struct propagate_block_info *pbi;
rtx insn, prev;
- pbi = init_propagate_block_info (bb, live, local_set, flags);
+ pbi = init_propagate_block_info (bb, live, local_set, cond_local_set, flags);
if (flags & PROP_REG_INFO)
{
@@ -4635,7 +4668,16 @@ mark_set_1 (pbi, code, reg, cond, insn, flags)
{
int needed_regno = REGNO_REG_SET_P (pbi->reg_live, i);
if (pbi->local_set)
- SET_REGNO_REG_SET (pbi->local_set, i);
+ {
+ /* Order of the set operation matters here since both
+ sets may be the same. */
+ CLEAR_REGNO_REG_SET (pbi->cond_local_set, i);
+ if (cond != NULL_RTX
+ && ! REGNO_REG_SET_P (pbi->local_set, i))
+ SET_REGNO_REG_SET (pbi->cond_local_set, i);
+ else
+ SET_REGNO_REG_SET (pbi->local_set, i);
+ }
if (code != CLOBBER)
SET_REGNO_REG_SET (pbi->new_set, i);
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 6ad1d35..e4955a7 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -1973,7 +1973,7 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
/* ??? bb->local_set is only valid during calculate_global_regs_live,
so we must recompute usage for MERGE_BB. Not so bad, I suppose,
since we've already asserted that MERGE_BB is small. */
- propagate_block (merge_bb, tmp, merge_set, 0);
+ propagate_block (merge_bb, tmp, merge_set, merge_set, 0);
/* For small register class machines, don't lengthen lifetimes of
hard registers before reload. */
@@ -1993,7 +1993,8 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
Moreover, we're interested in the insns live from OTHER_BB. */
COPY_REG_SET (test_live, other_bb->global_live_at_start);
- pbi = init_propagate_block_info (test_bb, test_live, test_set, 0);
+ pbi = init_propagate_block_info (test_bb, test_live, test_set, test_set,
+ 0);
for (insn = jump; ; insn = prev)
{
diff --git a/gcc/recog.c b/gcc/recog.c
index c01f884..4257d7c 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -3053,9 +3053,9 @@ peephole2_optimize (dump_file)
COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
#ifdef HAVE_conditional_execution
- pbi = init_propagate_block_info (bb, live, NULL, 0);
+ pbi = init_propagate_block_info (bb, live, NULL, NULL, 0);
#else
- pbi = init_propagate_block_info (bb, live, NULL, PROP_DEATH_NOTES);
+ pbi = init_propagate_block_info (bb, live, NULL, NULL, PROP_DEATH_NOTES);
#endif
for (insn = bb->end; ; insn = prev)