PR rtl-optimization/20070 / part1

PR rtl-optimization/20070 / part1
	* flow.c (update_life_info): If PROP_POST_REGSTACK is set, call
	count_or_remove_death_notes with kill == -1.
	(mark_set_1): Don't add REG_DEAD / REG_UNUSED notes for stack
	registers if PROP_POST_REGSTACK is set.
	(mark_used_reg): Likewise.
	(count_or_remove_death_notes): If kill is -1, don't remove REG_DEAD /
	REG_UNUSED notes for stack regs.
	* cfgcleanup.c (condjump_equiv_p): Change parameters and processing
	to match rtx_equiv_p machinery.  Change caller.
	(outgoing_edges_match): Likewise.
	(try_crossjump_to_edge): Use struct_equiv_block_eq
	instead of flow_find_cross_jump.
	* basic-block.h (PROP_POST_REGSTACK, STRUCT_EQUIV_START): Define.
	(STRUCT_EQUIV_RERUN, STRUCT_EQUIV_FINAL): Likewise.
	(STRUCT_EQUIV_NEED_FULL_BLOCK, STRUCT_EQUIV_MATCH_JUMPS): Likewise.
	(STRUCT_EQUIV_MAX_LOCAL): Likewise.
	(struct struct_equiv_checkpoint, struct equiv_info): Likewise.
	(insns_match_p): Update prototype.
	(flow_find_cross_jump): Remove prototype.
	(struct_equiv_block_eq, struct_equiv_init): Declare.
	(rtx_equiv_p, condjump_equiv_p): Likewise.
	* struct-equiv.c: Include reload.h.
	(IMPOSSIBLE_MOVE_FACTOR): Define.
	(assign_reg_reg_set, struct_equiv_make_checkpoint): New functions.
	(struct_equiv_improve_checkpoint): Likewise.
	(struct_equiv_restore_checkpoint, rtx_equiv_p): Likewise.
	(set_dest_equiv_p, set_dest_addr_equiv_p, struct_equiv_init): Likewise.
	(struct_equiv_merge, find_dying_input): Likewise.
	(resolve_input_conflict, note_local_live): Likewise.
	(death_notes_match_p): Change parameters and processing
	to match rtx_equiv_p machinery.  Change caller.
	(insns_match_p): Likewise.
	(flow_find_cross_jump): Replace with:
	(struct_equiv_block_eq).

	Back out this change:
	2005-03-07  Kazu Hirata  <kazu@cs.umass.edu>
          * recog.c (verify_changes): Make it static.
          * recog.h: Remove the corresponding prototype.

From-SVN: r108480
This commit is contained in:
J"orn Rennecke 2005-12-13 13:04:18 +00:00 committed by Joern Rennecke
parent 80e6edb051
commit 7d22e8989c
7 changed files with 1499 additions and 198 deletions

View File

@ -1,3 +1,46 @@
2005-12-13 J"orn Rennecke <joern.rennecke@st.com>
PR rtl-optimization/20070 / part1
* flow.c (update_life_info): If PROP_POST_REGSTACK is set, call
count_or_remove_death_notes with kill == -1.
(mark_set_1): Don't add REG_DEAD / REG_UNUSED notes for stack
registers if PROP_POST_REGSTACK is set.
(mark_used_reg): Likewise.
(count_or_remove_death_notes): If kill is -1, don't remove REG_DEAD /
REG_UNUSED notes for stack regs.
* cfgcleanup.c (condjump_equiv_p): Change parameters and processing
to match rtx_equiv_p machinery. Change caller.
(outgoing_edges_match): Likewise.
(try_crossjump_to_edge): Use struct_equiv_block_eq
instead of flow_find_cross_jump.
* basic-block.h (PROP_POST_REGSTACK, STRUCT_EQUIV_START): Define.
(STRUCT_EQUIV_RERUN, STRUCT_EQUIV_FINAL): Likewise.
(STRUCT_EQUIV_NEED_FULL_BLOCK, STRUCT_EQUIV_MATCH_JUMPS): Likewise.
(STRUCT_EQUIV_MAX_LOCAL): Likewise.
(struct struct_equiv_checkpoint, struct equiv_info): Likewise.
(insns_match_p): Update prototype.
(flow_find_cross_jump): Remove prototype.
(struct_equiv_block_eq, struct_equiv_init): Declare.
(rtx_equiv_p, condjump_equiv_p): Likewise.
* struct-equiv.c: Include reload.h.
(IMPOSSIBLE_MOVE_FACTOR): Define.
(assign_reg_reg_set, struct_equiv_make_checkpoint): New functions.
(struct_equiv_improve_checkpoint): Likewise.
(struct_equiv_restore_checkpoint, rtx_equiv_p): Likewise.
(set_dest_equiv_p, set_dest_addr_equiv_p, struct_equiv_init): Likewise.
(struct_equiv_merge, find_dying_input): Likewise.
(resolve_input_conflict, note_local_live): Likewise.
(death_notes_match_p): Change parameters and processing
to match rtx_equiv_p machinery. Change caller.
(insns_match_p): Likewise.
(flow_find_cross_jump): Replace with:
(struct_equiv_block_eq).
Back out this change:
2005-03-07 Kazu Hirata <kazu@cs.umass.edu>
* recog.c (verify_changes): Make it static.
* recog.h: Remove the corresponding prototype.
2005-12-13 J"orn Rennecke <joern.rennecke@st.com>
* rtlhooks.c (gen_lowpart_general): Handle SUBREGs of floating point

View File

@ -807,6 +807,9 @@ enum update_life_extent
to flag analysis of asms. */
#define PROP_DEAD_INSN 1024 /* Internal flag used within flow.c
to flag analysis of dead insn. */
#define PROP_POST_REGSTACK 2048 /* We run after reg-stack and need
to preserve REG_DEAD notes for
stack regs. */
#define PROP_FINAL (PROP_DEATH_NOTES | PROP_LOG_LINKS \
| PROP_REG_INFO | PROP_KILL_DEAD_CODE \
| PROP_SCAN_DEAD_CODE | PROP_AUTOINC \
@ -831,6 +834,17 @@ enum update_life_extent
#define CLEANUP_CFGLAYOUT 128 /* Do cleanup in cfglayout mode. */
#define CLEANUP_LOG_LINKS 256 /* Update log links. */
/* The following are ORed in on top of the CLEANUP* flags in calls to
struct_equiv_block_eq. */
#define STRUCT_EQUIV_START 512 /* Initializes the search range. */
#define STRUCT_EQUIV_RERUN 1024 /* Rerun to find register use in
found equivalence. */
#define STRUCT_EQUIV_FINAL 2048 /* Make any changes necessary to get
actual equivalence. */
#define STRUCT_EQUIV_NEED_FULL_BLOCK 4096 /* struct_equiv_block_eq is required
to match only full blocks */
#define STRUCT_EQUIV_MATCH_JUMPS 8192 /* Also include the jumps at the end of the block in the comparison. */
extern void life_analysis (FILE *, int);
extern int update_life_info (sbitmap, enum update_life_extent, int);
extern int update_life_info_in_dirty_blocks (enum update_life_extent, int);
@ -992,7 +1006,168 @@ extern basic_block get_bb_copy (basic_block);
#include "cfghooks.h"
/* In struct-equiv.c */
extern bool insns_match_p (int, rtx, rtx);
extern int flow_find_cross_jump (int, basic_block, basic_block, rtx *, rtx *);
/* Constants used to size arrays in struct equiv_info (currently only one).
When these limits are exceeded, struct_equiv returns zero.
The maximum number of pseudo registers that are different in the two blocks,
but appear in equivalent places and are dead at the end (or where one of
a pair is dead at the end). */
#define STRUCT_EQUIV_MAX_LOCAL 16
/* The maximum number of references to an input register that struct_equiv
can handle. */
/* Structure used to track state during struct_equiv that can be rolled
back when we find we can't match an insn, or if we want to match part
of it in a different way.
This information pertains to the pair of partial blocks that has been
matched so far. Since this pair is structurally equivalent, this is
conceptually just one partial block expressed in two potentially
different ways. */
struct struct_equiv_checkpoint
{
int ninsns; /* Insns are matched so far. */
int local_count; /* Number of block-local registers. */
int input_count; /* Number of inputs to the block. */
/* X_START and Y_START are the first insns (in insn stream order)
of the partial blocks that have been considered for matching so far.
Since we are scanning backwards, they are also the instructions that
are currently considered - or the last ones that have been considered -
for matching (Unless we tracked back to these because a preceding
instruction failed to match). */
rtx x_start, y_start;
/* INPUT_VALID indicates if we have actually set up X_INPUT / Y_INPUT
during the current pass; we keep X_INPUT / Y_INPUT around between passes
so that we can match REG_EQUAL / REG_EQUIV notes referring to these. */
bool input_valid;
/* Some information would be expensive to exactly checkpoint, so we
merely increment VERSION any time information about local
registers, inputs and/or register liveness changes. When backtracking,
it is decremented for changes that can be undone, and if a discrepancy
remains, NEED_RERUN in the relevant struct equiv_info is set to indicate
that a new pass should be made over the entire block match to get
accurate register information. */
int version;
};
/* A struct equiv_info is used to pass information to struct_equiv and
to gather state while two basic blocks are checked for structural
equivalence. */
struct equiv_info
{
/* Fields set up by the caller to struct_equiv_block_eq */
basic_block x_block, y_block; /* The two blocks being matched. */
/* MODE carries the mode bits from cleanup_cfg if we are called from
try_crossjump_to_edge, and additionally it carries the
STRUCT_EQUIV_* bits described above. */
int mode;
/* INPUT_COST is the cost that adding an extra input to the matched blocks
is supposed to have, and is taken into account when considering if the
matched sequence should be extended backwards. input_cost < 0 means
don't accept any inputs at all. */
int input_cost;
/* Fields to track state inside of struct_equiv_block_eq. Some of these
are also outputs. */
/* X_INPUT and Y_INPUT are used by struct_equiv to record a register that
is used as an input parameter, i.e. where different registers are used
as sources. This is only used for a register that is live at the end
of the blocks, or in some identical code at the end of the blocks;
Inputs that are dead at the end go into X_LOCAL / Y_LOCAL. */
rtx x_input, y_input;
/* When a previous pass has identified a valid input, INPUT_REG is set
by struct_equiv_block_eq, and it is henceforth replaced in X_BLOCK
for the input. */
rtx input_reg;
/* COMMON_LIVE keeps track of the registers which are currently live
(as we scan backwards from the end) and have the same numbers in both
blocks. N.B. a register that is in common_live is unsuitable to become
a local reg. */
regset common_live;
/* Likewise, X_LOCAL_LIVE / Y_LOCAL_LIVE keep track of registers that are
local to one of the blocks; these registers must not be accepted as
identical when encountered in both blocks. */
regset x_local_live, y_local_live;
/* EQUIV_USED indicates for which insns a REG_EQUAL or REG_EQUIV note is
being used, to avoid having to backtrack in the next pass, so that we
get accurate life info for this insn then. For each such insn,
the bit with the number corresponding to the CUR.NINSNS value at the
time of scanning is set. */
bitmap equiv_used;
/* Current state that can be saved & restored easily. */
struct struct_equiv_checkpoint cur;
/* BEST_MATCH is used to store the best match so far, weighing the
cost of matched insns COSTS_N_INSNS (CUR.NINSNS) against the cost
CUR.INPUT_COUNT * INPUT_COST of setting up the inputs. */
struct struct_equiv_checkpoint best_match;
/* If a checkpoint restore failed, or an input conflict newly arises,
NEED_RERUN is set. This has to be tested by the caller to re-run
the comparison if the match appears otherwise sound. The state kept in
x_start, y_start, equiv_used and check_input_conflict ensures that
we won't loop indefinetly. */
bool need_rerun;
/* If there is indication of an input conflict at the end,
CHECK_INPUT_CONFLICT is set so that we'll check for input conflicts
for each insn in the next pass. This is needed so that we won't discard
a partial match if there is a longer match that has to be abandoned due
to an input conflict. */
bool check_input_conflict;
/* HAD_INPUT_CONFLICT is set if CHECK_INPUT_CONFLICT was already set and we
have passed a point where there were multiple dying inputs. This helps
us decide if we should set check_input_conflict for the next pass. */
bool had_input_conflict;
/* LIVE_UPDATE controls if we want to change any life info at all. We
set it to false during REG_EQUAL / REG_EUQIV note comparison of the final
pass so that we don't introduce new registers just for the note; if we
can't match the notes without the current register information, we drop
them. */
bool live_update;
/* X_LOCAL and Y_LOCAL are used to gather register numbers of register pairs
that are local to X_BLOCK and Y_BLOCK, with CUR.LOCAL_COUNT being the index
to the next free entry. */
rtx x_local[STRUCT_EQUIV_MAX_LOCAL], y_local[STRUCT_EQUIV_MAX_LOCAL];
/* LOCAL_RVALUE is nonzero if the corresponding X_LOCAL / Y_LOCAL entry
was a source operand (including STRICT_LOW_PART) for the last invocation
of struct_equiv mentioning it, zero if it was a destination-only operand.
Since we are scanning backwards, this means the register is input/local
for the (partial) block scanned so far. */
bool local_rvalue[STRUCT_EQUIV_MAX_LOCAL];
/* Additional fields that are computed for the convenience of the caller. */
/* DYING_INPUTS is set to the number of local registers that turn out
to be inputs to the (possibly partial) block. */
int dying_inputs;
/* X_END and Y_END are the last insns in X_BLOCK and Y_BLOCK, respectively,
that are being compared. A final jump insn will not be included. */
rtx x_end, y_end;
/* If we are matching tablejumps, X_LABEL in X_BLOCK coresponds to
Y_LABEL in Y_BLOCK. */
rtx x_label, y_label;
};
extern bool insns_match_p (rtx, rtx, struct equiv_info *);
extern int struct_equiv_block_eq (int, struct equiv_info *);
extern bool struct_equiv_init (int, struct equiv_info *);
extern bool rtx_equiv_p (rtx *, rtx, int, struct equiv_info *);
/* In cfgrtl.c */
extern bool condjump_equiv_p (struct equiv_info *, bool);
#endif /* GCC_BASIC_BLOCK_H */

View File

@ -60,7 +60,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
static bool first_pass;
static bool try_crossjump_to_edge (int, edge, edge);
static bool try_crossjump_bb (int, basic_block);
static bool outgoing_edges_match (int, basic_block, basic_block);
static bool outgoing_edges_match (int *, struct equiv_info *);
static void merge_blocks_move_predecessor_nojumps (basic_block, basic_block);
static void merge_blocks_move_successor_nojumps (basic_block, basic_block);
@ -879,20 +879,20 @@ merge_blocks_move (edge e, basic_block b, basic_block c, int mode)
}
/* Return true iff the condbranches at the end of BB1 and BB2 match. */
static bool
condjump_equiv_p (basic_block bb1, basic_block bb2)
bool
condjump_equiv_p (struct equiv_info *info, bool call_init)
{
edge b1, f1, b2, f2;
basic_block bb1 = info->x_block;
basic_block bb2 = info->y_block;
edge b1 = BRANCH_EDGE (bb1);
edge b2 = BRANCH_EDGE (bb2);
edge f1 = FALLTHRU_EDGE (bb1);
edge f2 = FALLTHRU_EDGE (bb2);
bool reverse, match;
rtx set1, set2, cond1, cond2;
rtx src1, src2;
enum rtx_code code1, code2;
b1 = BRANCH_EDGE (bb1);
b2 = BRANCH_EDGE (bb2);
f1 = FALLTHRU_EDGE (bb1);
f2 = FALLTHRU_EDGE (bb2);
/* Get around possible forwarders on fallthru edges. Other cases
should be optimized out already. */
if (FORWARDER_BLOCK_P (f1->dest))
@ -923,8 +923,10 @@ condjump_equiv_p (basic_block bb1, basic_block bb2)
!= (XEXP (SET_SRC (set2), 1) == pc_rtx))
reverse = !reverse;
cond1 = XEXP (SET_SRC (set1), 0);
cond2 = XEXP (SET_SRC (set2), 0);
src1 = SET_SRC (set1);
src2 = SET_SRC (set2);
cond1 = XEXP (src1, 0);
cond2 = XEXP (src2, 0);
code1 = GET_CODE (cond1);
if (reverse)
code2 = reversed_comparison_code (cond2, BB_END (bb2));
@ -934,15 +936,35 @@ condjump_equiv_p (basic_block bb1, basic_block bb2)
if (code2 == UNKNOWN)
return false;
if (call_init && !struct_equiv_init (STRUCT_EQUIV_START | info->mode, info))
gcc_unreachable ();
/* Make the sources of the pc sets unreadable so that when we call
insns_match_p it won't process them.
The death_notes_match_p from insns_match_p won't see the local registers
used for the pc set, but that could only cause missed optimizations when
there are actually condjumps that use stack registers. */
SET_SRC (set1) = pc_rtx;
SET_SRC (set2) = pc_rtx;
/* Verify codes and operands match. */
match = ((code1 == code2
&& rtx_renumbered_equal_p (XEXP (cond1, 0), XEXP (cond2, 0))
&& rtx_renumbered_equal_p (XEXP (cond1, 1), XEXP (cond2, 1)))
|| (code1 == swap_condition (code2)
&& rtx_renumbered_equal_p (XEXP (cond1, 1),
XEXP (cond2, 0))
&& rtx_renumbered_equal_p (XEXP (cond1, 0),
XEXP (cond2, 1))));
if (code1 == code2)
{
match = (insns_match_p (BB_END (bb1), BB_END (bb2), info)
&& rtx_equiv_p (&XEXP (cond1, 0), XEXP (cond2, 0), 1, info)
&& rtx_equiv_p (&XEXP (cond1, 1), XEXP (cond2, 1), 1, info));
}
else if (code1 == swap_condition (code2))
{
match = (insns_match_p (BB_END (bb1), BB_END (bb2), info)
&& rtx_equiv_p (&XEXP (cond1, 1), XEXP (cond2, 0), 1, info)
&& rtx_equiv_p (&XEXP (cond1, 0), XEXP (cond2, 1), 1, info));
}
else
match = false;
SET_SRC (set1) = src1;
SET_SRC (set2) = src2;
match &= verify_changes (0);
/* If we return true, we will join the blocks. Which means that
we will only have one branch prediction bit to work with. Thus
@ -971,7 +993,7 @@ condjump_equiv_p (basic_block bb1, basic_block bb2)
"Outcomes of branch in bb %i and %i differ too much (%i %i)\n",
bb1->index, bb2->index, b1->probability, prob2);
return false;
match = false;
}
}
@ -979,17 +1001,25 @@ condjump_equiv_p (basic_block bb1, basic_block bb2)
fprintf (dump_file, "Conditionals in bb %i and %i match.\n",
bb1->index, bb2->index);
if (!match)
cancel_changes (0);
return match;
}
/* Return true iff outgoing edges of BB1 and BB2 match, together with
the branch instruction. This means that if we commonize the control
flow before end of the basic block, the semantic remains unchanged.
/* Return true iff outgoing edges of INFO->y_block and INFO->x_block match,
together with the branch instruction. This means that if we commonize the
control flow before end of the basic block, the semantic remains unchanged.
If we need to compare jumps, we set STRUCT_EQUIV_MATCH_JUMPS in *MODE,
and pass *MODE to struct_equiv_init or assign it to INFO->mode, as
appropriate.
We may assume that there exists one edge with a common destination. */
static bool
outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
outgoing_edges_match (int *mode, struct equiv_info *info)
{
basic_block bb1 = info->y_block;
basic_block bb2 = info->x_block;
int nehedges1 = 0, nehedges2 = 0;
edge fallthru1 = 0, fallthru2 = 0;
edge e1, e2;
@ -1005,6 +1035,7 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
& (EDGE_COMPLEX | EDGE_FAKE)) == 0
&& (!JUMP_P (BB_END (bb2)) || simplejump_p (BB_END (bb2))));
*mode |= STRUCT_EQUIV_MATCH_JUMPS;
/* Match conditional jumps - this may get tricky when fallthru and branch
edges are crossed. */
if (EDGE_COUNT (bb1->succs) == 2
@ -1015,7 +1046,8 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
|| !any_condjump_p (BB_END (bb2))
|| !onlyjump_p (BB_END (bb2)))
return false;
return condjump_equiv_p (bb1, bb2);
info->mode = *mode;
return condjump_equiv_p (info, true);
}
/* Generic case - we are seeing a computed jump, table jump or trapping
@ -1063,31 +1095,22 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
identical = false;
}
if (identical)
if (identical
&& struct_equiv_init (STRUCT_EQUIV_START | *mode, info))
{
replace_label_data rr;
bool match;
/* Temporarily replace references to LABEL1 with LABEL2
/* Indicate that LABEL1 is to be replaced with LABEL2
in BB1->END so that we could compare the instructions. */
rr.r1 = label1;
rr.r2 = label2;
rr.update_label_nuses = false;
for_each_rtx (&BB_END (bb1), replace_label, &rr);
info->y_label = label1;
info->x_label = label2;
match = insns_match_p (mode, BB_END (bb1), BB_END (bb2));
match = insns_match_p (BB_END (bb1), BB_END (bb2), info);
if (dump_file && match)
fprintf (dump_file,
"Tablejumps in bb %i and %i match.\n",
bb1->index, bb2->index);
/* Set the original label in BB1->END because when deleting
a block whose end is a tablejump, the tablejump referenced
from the instruction is deleted too. */
rr.r1 = label2;
rr.r2 = label1;
for_each_rtx (&BB_END (bb1), replace_label, &rr);
return match;
}
}
@ -1097,7 +1120,8 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
/* First ensure that the instructions match. There may be many outgoing
edges so this test is generally cheaper. */
if (!insns_match_p (mode, BB_END (bb1), BB_END (bb2)))
if (!struct_equiv_init (STRUCT_EQUIV_START | *mode, info)
|| !insns_match_p (BB_END (bb1), BB_END (bb2), info))
return false;
/* Search the outgoing edges, ensure that the counts do match, find possible
@ -1163,14 +1187,13 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
static bool
try_crossjump_to_edge (int mode, edge e1, edge e2)
{
int nmatch;
int nmatch, i;
basic_block src1 = e1->src, src2 = e2->src;
basic_block redirect_to, redirect_from, to_remove;
rtx newpos1, newpos2;
edge s;
edge_iterator ei;
newpos1 = newpos2 = NULL_RTX;
struct equiv_info info;
rtx x_active, y_active;
/* If we have partitioned hot/cold basic blocks, it is a bad idea
to try this optimization.
@ -1217,19 +1240,66 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
return false;
/* Look for the common insn sequence, part the first ... */
if (!outgoing_edges_match (mode, src1, src2))
info.x_block = src2;
info.y_block = src1;
if (!outgoing_edges_match (&mode, &info))
return false;
/* ... and part the second. */
nmatch = flow_find_cross_jump (mode, src1, src2, &newpos1, &newpos2);
info.input_cost = optimize_size ? COSTS_N_INSNS (1) : -1;
nmatch = struct_equiv_block_eq (STRUCT_EQUIV_START | mode, &info);
/* Don't proceed with the crossjump unless we found a sufficient number
of matching instructions or the 'from' block was totally matched
(such that its predecessors will hopefully be redirected and the
block removed). */
if ((nmatch < PARAM_VALUE (PARAM_MIN_CROSSJUMP_INSNS))
&& (newpos1 != BB_HEAD (src1)))
if (!nmatch)
return false;
if ((nmatch -info.cur.input_count < PARAM_VALUE (PARAM_MIN_CROSSJUMP_INSNS))
&& (info.cur.y_start != BB_HEAD (src1)))
return false;
while (info.need_rerun)
{
nmatch = struct_equiv_block_eq (STRUCT_EQUIV_RERUN | mode, &info);
if (!nmatch)
return false;
if ((nmatch -info.cur.input_count < PARAM_VALUE (PARAM_MIN_CROSSJUMP_INSNS))
&& (info.cur.y_start != BB_HEAD (src1)))
return false;
}
nmatch = struct_equiv_block_eq (STRUCT_EQUIV_FINAL | mode, &info);
if ((nmatch -info.cur.input_count < PARAM_VALUE (PARAM_MIN_CROSSJUMP_INSNS))
&& (info.cur.y_start != BB_HEAD (src1)))
return false;
/* Skip possible basic block header. */
x_active = info.cur.x_start;
if (LABEL_P (x_active))
x_active = NEXT_INSN (x_active);
if (NOTE_P (x_active))
x_active = NEXT_INSN (x_active);
y_active = info.cur.y_start;
if (LABEL_P (y_active))
y_active = NEXT_INSN (y_active);
if (NOTE_P (y_active))
y_active = NEXT_INSN (y_active);
/* In order for this code to become active, either we have to be called
before reload, or struct_equiv_block_eq needs to add register scavenging
code to allocate input_reg after reload. */
if (info.input_reg)
{
emit_insn_before (gen_move_insn (info.input_reg, info.x_input),
x_active);
emit_insn_before (gen_move_insn (info.input_reg, info.y_input),
y_active);
}
for (i = 0; i < info.cur.local_count; i++)
if (info.local_rvalue[i])
emit_insn_before (gen_move_insn (info.x_local[i], info.y_local[i]),
y_active);
/* Here we know that the insns in the end of SRC1 which are common with SRC2
will be deleted.
@ -1265,30 +1335,36 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
/* Avoid splitting if possible. We must always split when SRC2 has
EH predecessor edges, or we may end up with basic blocks with both
normal and EH predecessor edges. */
if (newpos2 == BB_HEAD (src2)
if (info.cur.x_start == BB_HEAD (src2)
&& !(EDGE_PRED (src2, 0)->flags & EDGE_EH))
redirect_to = src2;
else
{
if (newpos2 == BB_HEAD (src2))
if (info.cur.x_start == BB_HEAD (src2))
{
/* Skip possible basic block header. */
if (LABEL_P (newpos2))
newpos2 = NEXT_INSN (newpos2);
if (NOTE_P (newpos2))
newpos2 = NEXT_INSN (newpos2);
if (LABEL_P (info.cur.x_start))
info.cur.x_start = NEXT_INSN (info.cur.x_start);
if (NOTE_P (info.cur.x_start))
info.cur.x_start = NEXT_INSN (info.cur.x_start);
}
if (dump_file)
fprintf (dump_file, "Splitting bb %i before %i insns\n",
src2->index, nmatch);
redirect_to = split_block (src2, PREV_INSN (newpos2))->dest;
redirect_to = split_block (src2, PREV_INSN (info.cur.x_start))->dest;
COPY_REG_SET (info.y_block->il.rtl->global_live_at_end,
info.x_block->il.rtl->global_live_at_end);
}
if (dump_file)
fprintf (dump_file,
"Cross jumping from bb %i to bb %i; %i common insns\n",
src1->index, src2->index, nmatch);
{
fprintf (dump_file, "Cross jumping from bb %i to bb %i; %i common insns",
src1->index, src2->index, nmatch);
if (info.cur.local_count)
fprintf (dump_file, ", %i local registers", info.cur.local_count);
fprintf (dump_file, "\n");
}
redirect_to->count += src1->count;
redirect_to->frequency += src1->frequency;
@ -1352,14 +1428,7 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
/* Edit SRC1 to go to REDIRECT_TO at NEWPOS1. */
/* Skip possible basic block header. */
if (LABEL_P (newpos1))
newpos1 = NEXT_INSN (newpos1);
if (NOTE_P (newpos1))
newpos1 = NEXT_INSN (newpos1);
redirect_from = split_block (src1, PREV_INSN (newpos1))->src;
redirect_from = split_block (src1, PREV_INSN (y_active))->src;
to_remove = single_succ (redirect_from);
redirect_edge_and_branch_force (single_succ_edge (redirect_from), redirect_to);

View File

@ -643,7 +643,8 @@ update_life_info (sbitmap blocks, enum update_life_extent extent,
/* If asked, remove notes from the blocks we'll update. */
if (extent == UPDATE_LIFE_GLOBAL_RM_NOTES)
count_or_remove_death_notes (blocks, 1);
count_or_remove_death_notes (blocks,
prop_flags & PROP_POST_REGSTACK ? -1 : 1);
}
/* Clear log links in case we are asked to (re)compute them. */
@ -2926,7 +2927,13 @@ mark_set_1 (struct propagate_block_info *pbi, enum rtx_code code, rtx reg, rtx c
if (flags & PROP_REG_INFO)
REG_N_DEATHS (regno_first) += 1;
if (flags & PROP_DEATH_NOTES)
if (flags & PROP_DEATH_NOTES
#ifdef STACK_REGS
&& (!(flags & PROP_POST_REGSTACK)
|| !IN_RANGE (REGNO (reg), FIRST_STACK_REG,
LAST_STACK_REG))
#endif
)
{
/* Note that dead stores have already been deleted
when possible. If we get here, we have found a
@ -2939,7 +2946,13 @@ mark_set_1 (struct propagate_block_info *pbi, enum rtx_code code, rtx reg, rtx c
}
else
{
if (flags & PROP_DEATH_NOTES)
if (flags & PROP_DEATH_NOTES
#ifdef STACK_REGS
&& (!(flags & PROP_POST_REGSTACK)
|| !IN_RANGE (REGNO (reg), FIRST_STACK_REG,
LAST_STACK_REG))
#endif
)
{
/* This is a case where we have a multi-word hard register
and some, but not all, of the words of the register are
@ -2998,7 +3011,12 @@ mark_set_1 (struct propagate_block_info *pbi, enum rtx_code code, rtx reg, rtx c
here and count it. */
else if (GET_CODE (reg) == SCRATCH)
{
if (flags & PROP_DEATH_NOTES)
if (flags & PROP_DEATH_NOTES
#ifdef STACK_REGS
&& (!(flags & PROP_POST_REGSTACK)
|| !IN_RANGE (REGNO (reg), FIRST_STACK_REG, LAST_STACK_REG))
#endif
)
REG_NOTES (insn)
= alloc_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (insn));
}
@ -3764,6 +3782,10 @@ mark_used_reg (struct propagate_block_info *pbi, rtx reg,
if (! some_was_live)
{
if ((pbi->flags & PROP_DEATH_NOTES)
#ifdef STACK_REGS
&& (!(pbi->flags & PROP_POST_REGSTACK)
|| !IN_RANGE (REGNO (reg), FIRST_STACK_REG, LAST_STACK_REG))
#endif
&& ! find_regno_note (insn, REG_DEAD, regno_first))
REG_NOTES (insn)
= alloc_EXPR_LIST (REG_DEAD, reg, REG_NOTES (insn));
@ -4385,7 +4407,9 @@ struct tree_opt_pass pass_recompute_reg_usage =
/* Optionally removes all the REG_DEAD and REG_UNUSED notes from a set of
blocks. If BLOCKS is NULL, assume the universal set. Returns a count
of the number of registers that died. */
of the number of registers that died.
If KILL is 1, remove old REG_DEAD / REG_UNUSED notes. If it is 0, don't.
if it is -1, remove them unless they pertain to a stack reg. */
int
count_or_remove_death_notes (sbitmap blocks, int kill)
@ -4457,7 +4481,14 @@ count_or_remove_death_notes_bb (basic_block bb, int kill)
/* Fall through. */
case REG_UNUSED:
if (kill)
if (kill > 0
|| (kill
#ifdef STACK_REGS
&& (!REG_P (XEXP (link, 0))
|| !IN_RANGE (REGNO (XEXP (link, 0)),
FIRST_STACK_REG, LAST_STACK_REG))
#endif
))
{
rtx next = XEXP (link, 1);
free_EXPR_LIST_node (link);

View File

@ -339,7 +339,7 @@ num_changes_pending (void)
/* Tentatively apply the changes numbered NUM and up.
Return 1 if all changes are valid, zero otherwise. */
static int
int
verify_changes (int num)
{
int i;

View File

@ -76,6 +76,7 @@ extern int asm_operand_ok (rtx, const char *);
extern int validate_change (rtx, rtx *, rtx, int);
extern int validate_change_maybe_volatile (rtx, rtx *, rtx);
extern int insn_invalid_p (rtx);
extern int verify_changes (int);
extern void confirm_change_group (void);
extern int apply_change_group (void);
extern int num_validated_changes (void);

File diff suppressed because it is too large Load Diff