struct-equiv.c: Remove file.
2008-03-02 Andi Kleen <ak@suse.de> Richard Guenther <rguenther@suse.de> * struct-equiv.c: Remove file. * cfg_cleanup.c (condjump_equiv_p): Remove. * Makefile.in (OBJS-common): Remove struct-equiv.o. (struct-equiv.o): Remove rule. * basic-block.h (struct_equiv_checkpoint, STRUCT_EQUIV_*, insns_match_p, struct_equiv_block_eq, struct_equiv_init, rtx_equiv_p, condjump_equiv_p): Remove prototypes. Co-Authored-By: Richard Guenther <rguenther@suse.de> From-SVN: r132814
This commit is contained in:
parent
363d536b17
commit
f3130d75de
@ -1,3 +1,14 @@
|
||||
2008-03-02 Andi Kleen <ak@suse.de>
|
||||
Richard Guenther <rguenther@suse.de>
|
||||
|
||||
* struct-equiv.c: Remove file.
|
||||
* cfg_cleanup.c (condjump_equiv_p): Remove.
|
||||
* Makefile.in (OBJS-common): Remove struct-equiv.o.
|
||||
(struct-equiv.o): Remove rule.
|
||||
* basic-block.h (struct_equiv_checkpoint, STRUCT_EQUIV_*,
|
||||
insns_match_p, struct_equiv_block_eq, struct_equiv_init,
|
||||
rtx_equiv_p, condjump_equiv_p): Remove prototypes.
|
||||
|
||||
2008-03-01 Alexandre Oliva <aoliva@redhat.com>
|
||||
|
||||
* ifcvt.c (noce_process_if_block): Try to handle only the then
|
||||
|
@ -1138,7 +1138,6 @@ OBJS-common = \
|
||||
stmt.o \
|
||||
stor-layout.o \
|
||||
stringpool.o \
|
||||
struct-equiv.o \
|
||||
targhooks.o \
|
||||
timevar.o \
|
||||
toplev.o \
|
||||
@ -2677,10 +2676,6 @@ cfgloopanal.o : cfgloopanal.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
|
||||
$(OBSTACK_H) output.h graphds.h
|
||||
graphds.o : graphds.c graphds.h $(CONFIG_H) $(SYSTEM_H) bitmap.h $(OBSTACK_H) \
|
||||
coretypes.h vec.h vecprim.h
|
||||
struct-equiv.o : struct-equiv.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
|
||||
$(RTL_H) hard-reg-set.h output.h $(FLAGS_H) $(RECOG_H) \
|
||||
insn-config.h $(TARGET_H) $(TM_P_H) $(PARAMS_H) \
|
||||
$(REGS_H) $(EMIT_RTL_H) $(DF_H)
|
||||
loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \
|
||||
hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H) \
|
||||
output.h intl.h $(DF_H) $(HASHTAB_H)
|
||||
|
@ -805,17 +805,6 @@ edge find_edge (basic_block, basic_block);
|
||||
insns. */
|
||||
#define CLEANUP_CFGLAYOUT 32 /* Do cleanup in cfglayout mode. */
|
||||
|
||||
/* The following are ORed in on top of the CLEANUP* flags in calls to
|
||||
struct_equiv_block_eq. */
|
||||
#define STRUCT_EQUIV_START 64 /* Initializes the search range. */
|
||||
#define STRUCT_EQUIV_RERUN 128 /* Rerun to find register use in
|
||||
found equivalence. */
|
||||
#define STRUCT_EQUIV_FINAL 256 /* Make any changes necessary to get
|
||||
actual equivalence. */
|
||||
#define STRUCT_EQUIV_NEED_FULL_BLOCK 512 /* struct_equiv_block_eq is required
|
||||
to match only full blocks */
|
||||
#define STRUCT_EQUIV_MATCH_JUMPS 1024 /* Also include the jumps at the end of the block in the comparison. */
|
||||
|
||||
/* In lcm.c */
|
||||
extern struct edge_list *pre_edge_lcm (int, sbitmap *, sbitmap *,
|
||||
sbitmap *, sbitmap *, sbitmap **,
|
||||
@ -955,171 +944,6 @@ extern rtx insert_insn_end_bb_new (rtx, basic_block);
|
||||
|
||||
#include "cfghooks.h"
|
||||
|
||||
/* In struct-equiv.c */
|
||||
|
||||
/* 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 indefinitely. */
|
||||
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 corresponds 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 cfgcleanup.c */
|
||||
extern bool condjump_equiv_p (struct equiv_info *, bool);
|
||||
|
||||
/* Return true when one of the predecessor edges of BB is marked with EDGE_EH. */
|
||||
static inline bool
|
||||
bb_has_eh_pred (basic_block bb)
|
||||
|
128
gcc/cfgcleanup.c
128
gcc/cfgcleanup.c
@ -1134,134 +1134,6 @@ flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1,
|
||||
return ninsns;
|
||||
}
|
||||
|
||||
/* Return true iff the condbranches at the end of BB1 and BB2 match. */
|
||||
bool
|
||||
condjump_equiv_p (struct equiv_info *info, bool call_init)
|
||||
{
|
||||
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;
|
||||
|
||||
/* Get around possible forwarders on fallthru edges. Other cases
|
||||
should be optimized out already. */
|
||||
if (FORWARDER_BLOCK_P (f1->dest))
|
||||
f1 = single_succ_edge (f1->dest);
|
||||
|
||||
if (FORWARDER_BLOCK_P (f2->dest))
|
||||
f2 = single_succ_edge (f2->dest);
|
||||
|
||||
/* To simplify use of this function, return false if there are
|
||||
unneeded forwarder blocks. These will get eliminated later
|
||||
during cleanup_cfg. */
|
||||
if (FORWARDER_BLOCK_P (f1->dest)
|
||||
|| FORWARDER_BLOCK_P (f2->dest)
|
||||
|| FORWARDER_BLOCK_P (b1->dest)
|
||||
|| FORWARDER_BLOCK_P (b2->dest))
|
||||
return false;
|
||||
|
||||
if (f1->dest == f2->dest && b1->dest == b2->dest)
|
||||
reverse = false;
|
||||
else if (f1->dest == b2->dest && b1->dest == f2->dest)
|
||||
reverse = true;
|
||||
else
|
||||
return false;
|
||||
|
||||
set1 = pc_set (BB_END (bb1));
|
||||
set2 = pc_set (BB_END (bb2));
|
||||
if ((XEXP (SET_SRC (set1), 1) == pc_rtx)
|
||||
!= (XEXP (SET_SRC (set2), 1) == pc_rtx))
|
||||
reverse = !reverse;
|
||||
|
||||
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));
|
||||
else
|
||||
code2 = GET_CODE (cond2);
|
||||
|
||||
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. */
|
||||
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
|
||||
we require the existing branches to have probabilities that are
|
||||
roughly similar. */
|
||||
if (match
|
||||
&& !optimize_size
|
||||
&& maybe_hot_bb_p (bb1)
|
||||
&& maybe_hot_bb_p (bb2))
|
||||
{
|
||||
int prob2;
|
||||
|
||||
if (b1->dest == b2->dest)
|
||||
prob2 = b2->probability;
|
||||
else
|
||||
/* Do not use f2 probability as f2 may be forwarded. */
|
||||
prob2 = REG_BR_PROB_BASE - b2->probability;
|
||||
|
||||
/* Fail if the difference in probabilities is greater than 50%.
|
||||
This rules out two well-predicted branches with opposite
|
||||
outcomes. */
|
||||
if (abs (b1->probability - prob2) > REG_BR_PROB_BASE / 2)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file,
|
||||
"Outcomes of branch in bb %i and %i differ too much (%i %i)\n",
|
||||
bb1->index, bb2->index, b1->probability, prob2);
|
||||
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (dump_file && match)
|
||||
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.
|
||||
|
1339
gcc/struct-equiv.c
1339
gcc/struct-equiv.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user