diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2001-12-13 11:34:11 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2001-12-13 11:34:11 +0000 |
commit | ba38e12bb0d3217ec8d46df4431fff1f944e432e (patch) | |
tree | 370e6c425d4395a411fdf96a2629203ee94049f1 /gcc/cfgcleanup.c | |
parent | fd6162edabd7190d9e8d4c9eee3bea1eb59d2778 (diff) | |
download | gcc-ba38e12bb0d3217ec8d46df4431fff1f944e432e.tar.gz |
* predict.c (estimate_probability): Reorganize opcode heuristics.
* predict.def (PRED_OPCODE_POSITIVE, PRED_OPCODE_NONEQUAL,
PRED_FPOPCODE): New.
* i386.c (override_options): Recognize various CPU variants and set
SSE/MMX/3dNOW flags accordingly.
* i386.h (MASK_MMX_SET, MASK_SSE_SET, MASK_SSE2_SET, MASK_3DNOW_SET,
MASK_3DNOW_A_SET): New.
(MASK_ACCUMULATE_OUTGOING_ARGS_SET): New.
(MASK_NO_ACCUMULATE_OUTGOING_ARGS): Delete.
(MASK_*): Renumber.
(TARGET_FLAGS): Use new masks.
(CPP_CPU_SPECS): Recognize new CPU variants.
* invoke.texi (-mcpu): Update documentation.
* flags.h (flag_prefetch_loop_arrays): Declare.
* loop.h (LOOP_PREFETCH): Define new constant.
* loop.c (strength_reduce): Call emit_prefetch_instructions.
(MAX_PREFETCHES, PREFETCH_BLOCKS_BEFORE_LOOP_MAX,
PREFETCH_BLOCKS_BEFORE_LOOP_MIN, PREFETCH_BLOCKS_IN_LOOP_MIN): New
constants.
(check_store_data): New structure.
(check_store, emit_prefetch_instructions, rtx_equal_for_prefetch_p):
New functions.
* toplev.c: Include insn-flags.h.
(flag_prefetch_loop_arrays): New global variable.
(lang_independent_option): Add -fprefetch-loop-arrays.
(rest_of_compilation) Pass LOOP_PREFETCH when flag_prefetch_loop_arrays
is set.
* Makefile.in (toplev.c): Depend on insn-flags.h.
* invoke.texi (-fprefetch-loop-arrays): Document.
* predict.c (estimate_probability): Distribute the loop exit
probability according to number of exit edges.
* cfgcleanup.c (insns_match_p): Break out from ...;
(flow_find_cross_jump): ... here;
(outgoing_edges_match): Add parameter MODE; attempt to match everything
except for tablejumps.
(try_crossjump_to_edge): Accept complex edges.
(try_crossjump_bb): Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@47969 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cfgcleanup.c')
-rw-r--r-- | gcc/cfgcleanup.c | 284 |
1 files changed, 169 insertions, 115 deletions
diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index 526202a3f32..e7e31f94b6c 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -64,9 +64,11 @@ enum bb_flags { static bool try_crossjump_to_edge PARAMS ((int, edge, edge)); static bool try_crossjump_bb PARAMS ((int, basic_block)); -static bool outgoing_edges_match PARAMS ((basic_block, basic_block)); +static bool outgoing_edges_match PARAMS ((int, + basic_block, basic_block)); static int flow_find_cross_jump PARAMS ((int, basic_block, basic_block, rtx *, rtx *)); +static bool insns_match_p PARAMS ((int, rtx, rtx)); static bool delete_unreachable_blocks PARAMS ((void)); static bool label_is_jump_target_p PARAMS ((rtx, rtx)); @@ -546,6 +548,108 @@ merge_blocks (e, b, c, mode) return false; } + +/* Return true if I1 and I2 are equivalent and thus can be crossjumped. */ + +static bool +insns_match_p (mode, i1, i2) + int mode; + rtx i1, i2; +{ + rtx p1, p2; + + /* Verify that I1 and I2 are equivalent. */ + if (GET_CODE (i1) != GET_CODE (i2)) + return false; + + p1 = PATTERN (i1); + p2 = PATTERN (i2); + + if (GET_CODE (p1) != GET_CODE (p2)) + return false; + + /* If this is a CALL_INSN, compare register usage information. + If we don't check this on stack register machines, the two + CALL_INSNs might be merged leaving reg-stack.c with mismatching + numbers of stack registers in the same basic block. + If we don't check this on machines with delay slots, a delay slot may + be filled that clobbers a parameter expected by the subroutine. + + ??? We take the simple route for now and assume that if they're + equal, they were constructed identically. */ + + if (GET_CODE (i1) == CALL_INSN + && !rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1), + CALL_INSN_FUNCTION_USAGE (i2))) + return false; + +#ifdef STACK_REGS + /* If cross_jump_death_matters is not 0, the insn's mode + indicates whether or not the insn contains any stack-like + regs. */ + + if ((mode & CLEANUP_POST_REGSTACK) && stack_regs_mentioned (i1)) + { + /* If register stack conversion has already been done, then + death notes must also be compared before it is certain that + the two instruction streams match. */ + + rtx note; + HARD_REG_SET i1_regset, i2_regset; + + CLEAR_HARD_REG_SET (i1_regset); + CLEAR_HARD_REG_SET (i2_regset); + + for (note = REG_NOTES (i1); note; note = XEXP (note, 1)) + if (REG_NOTE_KIND (note) == REG_DEAD && STACK_REG_P (XEXP (note, 0))) + SET_HARD_REG_BIT (i1_regset, REGNO (XEXP (note, 0))); + + for (note = REG_NOTES (i2); note; note = XEXP (note, 1)) + if (REG_NOTE_KIND (note) == REG_DEAD && STACK_REG_P (XEXP (note, 0))) + SET_HARD_REG_BIT (i2_regset, REGNO (XEXP (note, 0))); + + GO_IF_HARD_REG_EQUAL (i1_regset, i2_regset, done); + + return false; + + done: + ; + } +#endif + + if (reload_completed + ? ! rtx_renumbered_equal_p (p1, p2) : ! rtx_equal_p (p1, p2)) + { + /* The following code helps take care of G++ cleanups. */ + rtx equiv1 = find_reg_equal_equiv_note (i1); + rtx equiv2 = find_reg_equal_equiv_note (i2); + + if (equiv1 && equiv2 + /* If the equivalences are not to a constant, they may + reference pseudos that no longer exist, so we can't + use them. */ + && (! reload_completed + || (CONSTANT_P (XEXP (equiv1, 0)) + && rtx_equal_p (XEXP (equiv1, 0), XEXP (equiv2, 0))))) + { + rtx s1 = single_set (i1); + rtx s2 = single_set (i2); + if (s1 != 0 && s2 != 0 + && rtx_renumbered_equal_p (SET_DEST (s1), SET_DEST (s2))) + { + validate_change (i1, &SET_SRC (s1), XEXP (equiv1, 0), 1); + validate_change (i2, &SET_SRC (s2), XEXP (equiv2, 0), 1); + if (! rtx_renumbered_equal_p (p1, p2)) + cancel_changes (0); + else if (apply_change_group ()) + return true; + } + } + return false; + } + return true; +} + /* Look through the insns at the end of BB1 and BB2 and find the longest sequence that are equivalent. Store the first insns for that sequence in *F1 and *F2 and return the sequence length. @@ -559,7 +663,7 @@ flow_find_cross_jump (mode, bb1, bb2, f1, f2) basic_block bb1, bb2; rtx *f1, *f2; { - rtx i1, i2, p1, p2, last1, last2, afterlast1, afterlast2; + rtx i1, i2, last1, last2, afterlast1, afterlast2; int ninsns = 0; /* Skip simple jumps at the end of the blocks. Complex jumps still @@ -586,100 +690,11 @@ flow_find_cross_jump (mode, bb1, bb2, f1, f2) if (i1 == bb1->head || i2 == bb2->head) break; - /* Verify that I1 and I2 are equivalent. */ - - if (GET_CODE (i1) != GET_CODE (i2)) - break; - - p1 = PATTERN (i1); - p2 = PATTERN (i2); - - /* If this is a CALL_INSN, compare register usage information. - If we don't check this on stack register machines, the two - CALL_INSNs might be merged leaving reg-stack.c with mismatching - numbers of stack registers in the same basic block. - If we don't check this on machines with delay slots, a delay slot may - be filled that clobbers a parameter expected by the subroutine. - - ??? We take the simple route for now and assume that if they're - equal, they were constructed identically. */ - - if (GET_CODE (i1) == CALL_INSN - && ! rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1), - CALL_INSN_FUNCTION_USAGE (i2))) + if (!insns_match_p (mode, i1, i2)) break; -#ifdef STACK_REGS - /* If cross_jump_death_matters is not 0, the insn's mode - indicates whether or not the insn contains any stack-like - regs. */ - - if ((mode & CLEANUP_POST_REGSTACK) && stack_regs_mentioned (i1)) - { - /* If register stack conversion has already been done, then - death notes must also be compared before it is certain that - the two instruction streams match. */ - - rtx note; - HARD_REG_SET i1_regset, i2_regset; - - CLEAR_HARD_REG_SET (i1_regset); - CLEAR_HARD_REG_SET (i2_regset); - - for (note = REG_NOTES (i1); note; note = XEXP (note, 1)) - if (REG_NOTE_KIND (note) == REG_DEAD - && STACK_REG_P (XEXP (note, 0))) - SET_HARD_REG_BIT (i1_regset, REGNO (XEXP (note, 0))); - - for (note = REG_NOTES (i2); note; note = XEXP (note, 1)) - if (REG_NOTE_KIND (note) == REG_DEAD - && STACK_REG_P (XEXP (note, 0))) - SET_HARD_REG_BIT (i2_regset, REGNO (XEXP (note, 0))); - - GO_IF_HARD_REG_EQUAL (i1_regset, i2_regset, done); - - break; - - done: - ; - } -#endif - - if (GET_CODE (p1) != GET_CODE (p2)) - break; - - if (! rtx_renumbered_equal_p (p1, p2)) - { - /* The following code helps take care of G++ cleanups. */ - rtx equiv1 = find_reg_equal_equiv_note (i1); - rtx equiv2 = find_reg_equal_equiv_note (i2); - - if (equiv1 && equiv2 - /* If the equivalences are not to a constant, they may - reference pseudos that no longer exist, so we can't - use them. */ - && CONSTANT_P (XEXP (equiv1, 0)) - && rtx_equal_p (XEXP (equiv1, 0), XEXP (equiv2, 0))) - { - rtx s1 = single_set (i1); - rtx s2 = single_set (i2); - if (s1 != 0 && s2 != 0 - && rtx_renumbered_equal_p (SET_DEST (s1), SET_DEST (s2))) - { - validate_change (i1, &SET_SRC (s1), XEXP (equiv1, 0), 1); - validate_change (i2, &SET_SRC (s2), XEXP (equiv2, 0), 1); - if (! rtx_renumbered_equal_p (p1, p2)) - cancel_changes (0); - else if (apply_change_group ()) - goto win; - } - } - break; - } - - win: /* Don't begin a cross-jump with a USE or CLOBBER insn. */ - if (GET_CODE (p1) != USE && GET_CODE (p1) != CLOBBER) + if (active_insn_p (i1)) { /* If the merged insns have different REG_EQUAL notes, then remove them. */ @@ -743,10 +758,15 @@ flow_find_cross_jump (mode, bb1, bb2, f1, f2) We may assume that there exists one edge with a common destination. */ static bool -outgoing_edges_match (bb1, bb2) +outgoing_edges_match (mode, bb1, bb2) + int mode; basic_block bb1; basic_block bb2; { + int nehedges1 = 0, nehedges2 = 0; + edge fallthru1 = 0, fallthru2 = 0; + edge e1, e2; + /* If BB1 has only one successor, we must be looking at an unconditional jump. Which, by the assumption above, means that we only need to check that BB2 has one successor. */ @@ -862,10 +882,60 @@ outgoing_edges_match (bb1, bb2) return match; } - /* ??? We can handle computed jumps too. This may be important for - inlined functions containing switch statements. Also jumps w/o - fallthru edges can be handled by simply matching whole insn. */ - return false; + /* Generic case - we are seeing an computed jump, table jump or trapping + instruction. */ + + /* First ensure that the instructions match. There may be many outgoing + edges so this test is generally cheaper. + ??? Currently the tablejumps will never match, as they do have + different tables. */ + if (!insns_match_p (mode, bb1->end, bb2->end)) + return false; + + /* Search the outgoing edges, ensure that the counts do match, find possible + fallthru and exception handling edges since these needs more + validation. */ + for (e1 = bb1->succ, e2 = bb2->succ; e1 && e2; + e1 = e1->succ_next, e2 = e2->succ_next) + { + if (e1->flags & EDGE_EH) + nehedges1++; + if (e2->flags & EDGE_EH) + nehedges2++; + if (e1->flags & EDGE_FALLTHRU) + fallthru1 = e1; + if (e2->flags & EDGE_FALLTHRU) + fallthru2 = e2; + } + /* If number of edges of various types does not match, fail. */ + if (e1 || e2) + return false; + if (nehedges1 != nehedges2) + return false; + if ((fallthru1 != 0) != (fallthru2 != 0)) + return false; + + /* fallthru edges must be forwarded to the same destination. */ + if (fallthru1) + { + basic_block d1 = (forwarder_block_p (fallthru1->dest) + ? fallthru1->dest->succ->dest: fallthru1->dest); + basic_block d2 = (forwarder_block_p (fallthru2->dest) + ? fallthru2->dest->succ->dest: fallthru2->dest); + if (d1 != d2) + return false; + } + /* In case we do have EH edges, ensure we are in the same region. */ + if (nehedges1) + { + rtx n1 = find_reg_note (bb1->end, REG_EH_REGION, 0); + rtx n2 = find_reg_note (bb2->end, REG_EH_REGION, 0); + if (XEXP (n1, 0) != XEXP (n2, 0)) + return false; + } + /* We don't need to match the rest of edges as above checks should be enought + to ensure that they are equivalent. */ + return true; } /* E1 and E2 are edges with the same destination block. Search their @@ -924,14 +994,8 @@ try_crossjump_to_edge (mode, e1, e2) if (!src1->pred || !src2->pred) return false; - /* Likewise with complex edges. - ??? We should be able to handle most complex edges later with some - care. */ - if (e1->flags & EDGE_COMPLEX) - return false; - /* Look for the common insn sequence, part the first ... */ - if (!outgoing_edges_match (src1, src2)) + if (!outgoing_edges_match (mode, src1, src2)) return false; /* ... and part the second. */ @@ -1066,11 +1130,6 @@ try_crossjump_bb (mode, bb) { nexte = e->pred_next; - /* Elide complex edges now, as neither try_crossjump_to_edge - nor outgoing_edges_match can handle them. */ - if (e->flags & EDGE_COMPLEX) - continue; - /* As noted above, first try with the fallthru predecessor. */ if (fallthru) { @@ -1113,11 +1172,6 @@ try_crossjump_bb (mode, bb) if (e2 == fallthru) continue; - /* Again, neither try_crossjump_to_edge nor outgoing_edges_match - can handle complex edges. */ - if (e2->flags & EDGE_COMPLEX) - continue; - /* The "first successor" check above only prevents multiple checks of crossjump(A,B). In order to prevent redundant checks of crossjump(B,A), require that A be the block |