Hello,
here is a proposal for the patch to remove loop notes (I still need to
benchmark it, and probably split into smaller parts). However, I do not
understand some of the code from that it removes loop note usage, so I
would appreciate comments on them:
cse.c:cse_end_of_basic_block -- something related to jump following.
Steven, you had some patches towards removing this, right?
jump.c:follow_jumps -- claims something about creating loops with
multiple entries. However, it seemts to be only used in cse (that won't
affect cfg), and then in dbr_schedule (way after the point where we
care about loop structures).
*sched* -- no idea what happens there; it seems to make REG_SAVE_NOTE
notes from loop notes, and then makes some magic, but I do not
understand what and why.
config/sh/sh.c: sh_adjust_unroll_max seems unused,
sh_optimize_target_register_callee_saved contains some heuristics
based on loops, I have no idea how important that heuristics is
(and I do not have hardware to benchmark it).
Zdenek
Index: doc/tm.texi
===================================================================
*** doc/tm.texi (revision 111675)
--- doc/tm.texi (working copy)
*************** The maximum number of bytes to skip when
*** 7942,7949 ****
@end defmac
@defmac LOOP_ALIGN (@var{label})
! The alignment (log base 2) to put in front of @var{label}, which follows
! a @code{NOTE_INSN_LOOP_BEG} note.
This macro need not be defined if you don't want any special alignment
to be done at such a time. Most machine descriptions do not currently
--- 7942,7949 ----
@end defmac
@defmac LOOP_ALIGN (@var{label})
! The alignment (log base 2) to put in front of @var{label} at the beginning
! of the loop.
This macro need not be defined if you don't want any special alignment
to be done at such a time. Most machine descriptions do not currently
Index: doc/rtl.texi
===================================================================
*** doc/rtl.texi (revision 111675)
--- doc/rtl.texi (working copy)
*************** level of scoping for exception handling.
*** 3139,3168 ****
identifies which @code{CODE_LABEL} or @code{note} of type
@code{NOTE_INSN_DELETED_LABEL} is associated with the given region.
- @findex NOTE_INSN_LOOP_BEG
- @findex NOTE_INSN_LOOP_END
- @item NOTE_INSN_LOOP_BEG
- @itemx NOTE_INSN_LOOP_END
- These types of notes indicate the position of the beginning and end
- of a @code{while} or @code{for} loop. They enable the loop optimizer
- to find loops quickly.
-
- @findex NOTE_INSN_LOOP_CONT
- @item NOTE_INSN_LOOP_CONT
- Appears at the place in a loop that @code{continue} statements jump to.
-
- @findex NOTE_INSN_LOOP_VTOP
- @item NOTE_INSN_LOOP_VTOP
- This note indicates the place in a loop where the exit test begins for
- those loops in which the exit test has been duplicated. This position
- becomes another virtual start of the loop when considering loop
- invariants.
-
- @findex NOTE_INSN_FUNCTION_BEG
- @item NOTE_INSN_FUNCTION_BEG
- Appears at the start of the function body, after the function
- prologue.
-
@findex NOTE_INSN_FUNCTION_END
@item NOTE_INSN_FUNCTION_END
Appears near the end of the function body, just before the label that
--- 3139,3144 ----
Index: cfgloopmanip.c
===================================================================
*** cfgloopmanip.c (revision 111675)
--- cfgloopmanip.c (working copy)
*************** loop_split_edge_with (edge e, rtx insns)
*** 1275,1374 ****
return new_bb;
}
- /* Uses the natural loop discovery to recreate loop notes. */
- void
- create_loop_notes (void)
- {
- rtx insn, head, end;
- struct loops loops;
- struct loop *loop;
- basic_block *first, *last, bb, pbb;
- struct loop **stack, **top;
-
- #ifdef ENABLE_CHECKING
- /* Verify that there really are no loop notes. */
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- gcc_assert (!NOTE_P (insn) ||
- NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG);
- #endif
-
- flow_loops_find (&loops);
- free_dominance_info (CDI_DOMINATORS);
- if (loops.num > 1)
- {
- last = XCNEWVEC (basic_block, loops.num);
-
- FOR_EACH_BB (bb)
- {
- for (loop = bb->loop_father; loop->outer; loop = loop->outer)
- last[loop->num] = bb;
- }
-
- first = XCNEWVEC (basic_block, loops.num);
- stack = XCNEWVEC (struct loop *, loops.num);
- top = stack;
-
- FOR_EACH_BB (bb)
- {
- for (loop = bb->loop_father; loop->outer; loop = loop->outer)
- {
- if (!first[loop->num])
- {
- *top++ = loop;
- first[loop->num] = bb;
- }
-
- if (bb == last[loop->num])
- {
- /* Prevent loops from overlapping. */
- while (*--top != loop)
- last[(*top)->num] = EXIT_BLOCK_PTR;
-
- /* If loop starts with jump into it, place the note in
- front of the jump. */
- insn = PREV_INSN (BB_HEAD (first[loop->num]));
- if (insn
- && BARRIER_P (insn))
- insn = PREV_INSN (insn);
-
- if (insn
- && JUMP_P (insn)
- && any_uncondjump_p (insn)
- && onlyjump_p (insn))
- {
- pbb = BLOCK_FOR_INSN (insn);
- gcc_assert (pbb && single_succ_p (pbb));
-
- if (!flow_bb_inside_loop_p (loop, single_succ (pbb)))
- insn = BB_HEAD (first[loop->num]);
- }
- else
- insn = BB_HEAD (first[loop->num]);
-
- head = BB_HEAD (first[loop->num]);
- emit_note_before (NOTE_INSN_LOOP_BEG, insn);
- BB_HEAD (first[loop->num]) = head;
-
- /* Position the note correctly wrto barrier. */
- insn = BB_END (last[loop->num]);
- if (NEXT_INSN (insn)
- && BARRIER_P (NEXT_INSN (insn)))
- insn = NEXT_INSN (insn);
-
- end = BB_END (last[loop->num]);
- emit_note_after (NOTE_INSN_LOOP_END, insn);
- BB_END (last[loop->num]) = end;
- }
- }
- }
-
- free (first);
- free (last);
- free (stack);
- }
- flow_loops_free (&loops);
- }
-
/* This function is called from loop_version. It splits the entry edge
of the loop we want to version, adds the versioning condition, and
adjust the edges to the two versions of the loop appropriately.
--- 1275,1280 ----
Index: final.c
===================================================================
*** final.c (revision 111675)
--- final.c (working copy)
*************** shorten_branches (rtx first ATTRIBUTE_UN
*** 856,869 ****
INSN_SHUID (insn) = i++;
if (INSN_P (insn))
! {
! /* reorg might make the first insn of a loop being run once only,
! and delete the label in front of it. Then we want to apply
! the loop alignment to the new label created by reorg, which
! is separated by the former loop start insn from the
! NOTE_INSN_LOOP_BEG. */
! }
! else if (LABEL_P (insn))
{
rtx next;
--- 856,864 ----
INSN_SHUID (insn) = i++;
if (INSN_P (insn))
! continue;
!
! if (LABEL_P (insn))
{
rtx next;
*************** final_scan_insn (rtx insn, FILE *file, i
*** 1703,1710 ****
switch (NOTE_LINE_NUMBER (insn))
{
case NOTE_INSN_DELETED:
- case NOTE_INSN_LOOP_BEG:
- case NOTE_INSN_LOOP_END:
case NOTE_INSN_FUNCTION_END:
case NOTE_INSN_REPEATED_LINE_NUMBER:
case NOTE_INSN_EXPECTED_VALUE:
--- 1698,1703 ----
Index: insn-notes.def
===================================================================
*** insn-notes.def (revision 111675)
--- insn-notes.def (working copy)
*************** INSN_NOTE (DELETED_LABEL)
*** 43,52 ****
INSN_NOTE (BLOCK_BEG)
INSN_NOTE (BLOCK_END)
- /* These mark the extremes of a loop. */
- INSN_NOTE (LOOP_BEG)
- INSN_NOTE (LOOP_END)
-
/* This note indicates the start of the real body of the function,
i.e. the point just after all of the parms have been moved into
their homes, etc. */
--- 43,48 ----
Index: haifa-sched.c
===================================================================
*** haifa-sched.c (revision 111675)
--- haifa-sched.c (working copy)
*************** unlink_other_notes (rtx insn, rtx tail)
*** 989,997 ****
PREV_INSN (next) = prev;
/* See sched_analyze to see how these are handled. */
! if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
! && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END
! && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END)
{
--- 989,995 ----
PREV_INSN (next) = prev;
/* See sched_analyze to see how these are handled. */
! if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END)
{
*************** move_insn1 (rtx insn, rtx last)
*** 1615,1621 ****
}
/* Search INSN for REG_SAVE_NOTE note pairs for
! NOTE_INSN_{LOOP,EHREGION}_{BEG,END}; and convert them back into
NOTEs. The REG_SAVE_NOTE note following first one is contains the
saved value for NOTE_BLOCK_NUMBER which is useful for
NOTE_INSN_EH_REGION_{BEG,END} NOTEs. LAST is the last instruction
--- 1613,1619 ----
}
/* Search INSN for REG_SAVE_NOTE note pairs for
! NOTE_INSN_EHREGION_{BEG,END}; and convert them back into
NOTEs. The REG_SAVE_NOTE note following first one is contains the
saved value for NOTE_BLOCK_NUMBER which is useful for
NOTE_INSN_EH_REGION_{BEG,END} NOTEs. LAST is the last instruction
Index: cse.c
===================================================================
*** cse.c (revision 111675)
--- cse.c (working copy)
*************** cse_end_of_basic_block (rtx insn, struct
*** 6696,6702 ****
{
for (q = PREV_INSN (JUMP_LABEL (p)); q; q = PREV_INSN (q))
if ((!NOTE_P (q)
- || NOTE_LINE_NUMBER (q) == NOTE_INSN_LOOP_END
|| (PREV_INSN (q) && CALL_P (PREV_INSN (q))
&& find_reg_note (PREV_INSN (q), REG_SETJMP, NULL)))
&& (!LABEL_P (q) || LABEL_NUSES (q) != 0))
--- 6696,6701 ----
Index: jump.c
===================================================================
*** jump.c (revision 111675)
--- jump.c (working copy)
*************** mark_all_labels (rtx f)
*** 260,270 ****
}
}
! /* Move all block-beg, block-end, loop-beg, loop-cont, loop-vtop, loop-end,
! notes between START and END out before START. START and END may be such
! notes. Returns the values of the new starting and ending insns, which
! may be different if the original ones were such notes.
! Return true if there were only such notes and no real instructions. */
bool
squeeze_notes (rtx* startp, rtx* endp)
--- 260,270 ----
}
}
! /* Move all block-beg, block-end and loop-beg notes between START and END out
! before START. START and END may be such notes. Returns the values of the
! new starting and ending insns, which may be different if the original ones
! were such notes. Return true if there were only such notes and no real
! instructions. */
bool
squeeze_notes (rtx* startp, rtx* endp)
*************** squeeze_notes (rtx* startp, rtx* endp)
*** 282,290 ****
next = NEXT_INSN (insn);
if (NOTE_P (insn)
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
! || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
! || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
! || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END))
{
/* BLOCK_BEG or BLOCK_END notes only exist in the `final' pass. */
gcc_assert (NOTE_LINE_NUMBER (insn) != NOTE_INSN_BLOCK_BEG
--- 282,288 ----
next = NEXT_INSN (insn);
if (NOTE_P (insn)
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
! || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG))
{
/* BLOCK_BEG or BLOCK_END notes only exist in the `final' pass. */
gcc_assert (NOTE_LINE_NUMBER (insn) != NOTE_INSN_BLOCK_BEG
*************** sets_cc0_p (rtx x)
*** 1041,1048 ****
If the chain loops or we can't find end, return LABEL,
since that tells caller to avoid changing the insn.
! If RELOAD_COMPLETED is 0, we do not chain across a NOTE_INSN_LOOP_BEG or
! a USE or CLOBBER. */
rtx
follow_jumps (rtx label)
--- 1039,1045 ----
If the chain loops or we can't find end, return LABEL,
since that tells caller to avoid changing the insn.
! If RELOAD_COMPLETED is 0, we do not chain across a USE or CLOBBER. */
rtx
follow_jumps (rtx label)
*************** follow_jumps (rtx label)
*** 1063,1081 ****
&& BARRIER_P (next));
depth++)
{
- /* Don't chain through the insn that jumps into a loop
- from outside the loop,
- since that would create multiple loop entry jumps
- and prevent loop optimization. */
rtx tem;
! if (!reload_completed)
! for (tem = value; tem != insn; tem = NEXT_INSN (tem))
! if (NOTE_P (tem)
! && (NOTE_LINE_NUMBER (tem) == NOTE_INSN_LOOP_BEG
! /* ??? Optional. Disables some optimizations, but makes
! gcov output more accurate with -O. */
! || (flag_test_coverage && NOTE_LINE_NUMBER (tem) > 0)))
! return value;
/* If we have found a cycle, make the insn jump to itself. */
if (JUMP_LABEL (insn) == label)
--- 1060,1074 ----
&& BARRIER_P (next));
depth++)
{
rtx tem;
! if (!reload_completed && flag_test_coverage)
! {
! /* ??? Optional. Disables some optimizations, but makes
! gcov output more accurate with -O. */
! for (tem = value; tem != insn; tem = NEXT_INSN (tem))
! if (NOTE_P (tem) && NOTE_LINE_NUMBER (tem) > 0)
! return value;
! }
/* If we have found a cycle, make the insn jump to itself. */
if (JUMP_LABEL (insn) == label)
Index: cfgcleanup.c
===================================================================
*** cfgcleanup.c (revision 111675)
--- cfgcleanup.c (working copy)
*************** rest_of_handle_jump2 (void)
*** 2312,2319 ****
cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0)
| (flag_thread_jumps ? CLEANUP_THREADING : 0));
- create_loop_notes ();
-
purge_line_number_notes ();
if (optimize)
--- 2312,2317 ----
Index: cfglayout.c
===================================================================
*** cfglayout.c (revision 111675)
--- cfglayout.c (working copy)
*************** skip_insns_after_block (basic_block bb)
*** 99,105 ****
case NOTE:
switch (NOTE_LINE_NUMBER (insn))
{
- case NOTE_INSN_LOOP_END:
case NOTE_INSN_BLOCK_END:
last_insn = insn;
continue;
--- 99,104 ----
*************** skip_insns_after_block (basic_block bb)
*** 135,146 ****
/* It is possible to hit contradictory sequence. For instance:
jump_insn
! NOTE_INSN_LOOP_BEG
barrier
Where barrier belongs to jump_insn, but the note does not. This can be
created by removing the basic block originally following
! NOTE_INSN_LOOP_BEG. In such case reorder the notes. */
for (insn = last_insn; insn != BB_END (bb); insn = prev)
{
--- 134,145 ----
/* It is possible to hit contradictory sequence. For instance:
jump_insn
! NOTE_INSN_BLOCK_BEG
barrier
Where barrier belongs to jump_insn, but the note does not. This can be
created by removing the basic block originally following
! NOTE_INSN_BLOCK_BEG. In such case reorder the notes. */
for (insn = last_insn; insn != BB_END (bb); insn = prev)
{
*************** skip_insns_after_block (basic_block bb)
*** 148,154 ****
if (NOTE_P (insn))
switch (NOTE_LINE_NUMBER (insn))
{
- case NOTE_INSN_LOOP_END:
case NOTE_INSN_BLOCK_END:
case NOTE_INSN_DELETED:
case NOTE_INSN_DELETED_LABEL:
--- 147,152 ----
*************** duplicate_insn_chain (rtx from, rtx to)
*** 986,995 ****
in first BB, we may want to copy the block. */
case NOTE_INSN_PROLOGUE_END:
- case NOTE_INSN_LOOP_BEG:
- case NOTE_INSN_LOOP_END:
- /* Strip down the loop notes - we don't really want to keep
- them consistent in loop copies. */
case NOTE_INSN_DELETED:
case NOTE_INSN_DELETED_LABEL:
/* No problem to strip these. */
--- 984,989 ----
Index: sched-deps.c
===================================================================
*** sched-deps.c (revision 111675)
--- sched-deps.c (working copy)
*************** static void fixup_sched_groups (rtx);
*** 96,102 ****
static void flush_pending_lists (struct deps *, rtx, int, int);
static void sched_analyze_1 (struct deps *, rtx, rtx);
static void sched_analyze_2 (struct deps *, rtx, rtx);
! static void sched_analyze_insn (struct deps *, rtx, rtx, rtx);
static rtx sched_get_condition (rtx);
static int conditions_mutex_p (rtx, rtx);
--- 96,102 ----
static void flush_pending_lists (struct deps *, rtx, int, int);
static void sched_analyze_1 (struct deps *, rtx, rtx);
static void sched_analyze_2 (struct deps *, rtx, rtx);
! static void sched_analyze_insn (struct deps *, rtx, rtx);
static rtx sched_get_condition (rtx);
static int conditions_mutex_p (rtx, rtx);
*************** sched_analyze_2 (struct deps *deps, rtx
*** 881,887 ****
/* Analyze an INSN with pattern X to find all dependencies. */
static void
! sched_analyze_insn (struct deps *deps, rtx x, rtx insn, rtx loop_notes)
{
RTX_CODE code = GET_CODE (x);
rtx link;
--- 881,887 ----
/* Analyze an INSN with pattern X to find all dependencies. */
static void
! sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
{
RTX_CODE code = GET_CODE (x);
rtx link;
*************** sched_analyze_insn (struct deps *deps, r
*** 1002,1029 ****
}
}
- /* If there is a {LOOP,EHREGION}_{BEG,END} note in the middle of a basic
- block, then we must be sure that no instructions are scheduled across it.
- Otherwise, the reg_n_refs info (which depends on loop_depth) would
- become incorrect. */
- if (loop_notes)
- {
- rtx link;
-
- /* Update loop_notes with any notes from this insn. */
- link = loop_notes;
- while (XEXP (link, 1))
- {
- gcc_assert (INTVAL (XEXP (link, 0)) == NOTE_INSN_LOOP_BEG
- || INTVAL (XEXP (link, 0)) == NOTE_INSN_LOOP_END);
-
- reg_pending_barrier = MOVE_BARRIER;
- link = XEXP (link, 1);
- }
- XEXP (link, 1) = REG_NOTES (insn);
- REG_NOTES (insn) = loop_notes;
- }
-
/* If this instruction can throw an exception, then moving it changes
where block boundaries fall. This is mighty confusing elsewhere.
Therefore, prevent such an instruction from being moved. */
--- 1002,1007 ----
*************** void
*** 1245,1251 ****
sched_analyze (struct deps *deps, rtx head, rtx tail)
{
rtx insn;
- rtx loop_notes = 0;
if (current_sched_info->use_cselib)
cselib_init (true);
--- 1223,1228 ----
*************** sched_analyze (struct deps *deps, rtx he
*** 1279,1286 ****
deps->last_pending_memory_flush
= alloc_INSN_LIST (insn, deps->last_pending_memory_flush);
}
! sched_analyze_insn (deps, PATTERN (insn), insn, loop_notes);
! loop_notes = 0;
}
else if (CALL_P (insn))
{
--- 1256,1262 ----
deps->last_pending_memory_flush
= alloc_INSN_LIST (insn, deps->last_pending_memory_flush);
}
! sched_analyze_insn (deps, PATTERN (insn), insn);
}
else if (CALL_P (insn))
{
*************** sched_analyze (struct deps *deps, rtx he
*** 1334,1341 ****
add_dependence_list_and_free (insn, &deps->sched_before_next_call, 1,
REG_DEP_ANTI);
! sched_analyze_insn (deps, PATTERN (insn), insn, loop_notes);
! loop_notes = 0;
/* In the absence of interprocedural alias analysis, we must flush
all pending reads and writes, and start new dependencies starting
--- 1310,1316 ----
add_dependence_list_and_free (insn, &deps->sched_before_next_call, 1,
REG_DEP_ANTI);
! sched_analyze_insn (deps, PATTERN (insn), insn);
/* In the absence of interprocedural alias analysis, we must flush
all pending reads and writes, and start new dependencies starting
*************** sched_analyze (struct deps *deps, rtx he
*** 1358,1376 ****
if (NOTE_P (insn))
gcc_assert (NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END);
-
- /* See comments on reemit_notes as to why we do this.
- ??? Actually, the reemit_notes just say what is done, not why. */
-
- if (NOTE_P (insn)
- && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
- || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END))
- {
- loop_notes = alloc_EXPR_LIST (REG_SAVE_NOTE,
- GEN_INT (NOTE_LINE_NUMBER (insn)),
- loop_notes);
- CONST_OR_PURE_CALL_P (loop_notes) = CONST_OR_PURE_CALL_P (insn);
- }
if (current_sched_info->use_cselib)
cselib_process_insn (insn);
--- 1333,1338 ----
Index: cfgloop.c
===================================================================
*** cfgloop.c (revision 111675)
--- cfgloop.c (working copy)
*************** flow_loop_dump (const struct loop *loop,
*** 127,134 ****
if (! loop || ! loop->header)
return;
! fprintf (file, ";;\n;; Loop %d:%s\n", loop->num,
! loop->invalid ? " invalid" : "");
fprintf (file, ";; header %d, latch %d\n",
loop->header->index, loop->latch->index);
--- 127,133 ----
if (! loop || ! loop->header)
return;
! fprintf (file, ";;\n;; Loop %d\n", loop->num);
fprintf (file, ";; header %d, latch %d\n",
loop->header->index, loop->latch->index);
Index: cfgloop.h
===================================================================
*** cfgloop.h (revision 111675)
--- cfgloop.h (working copy)
*************** struct loop
*** 78,91 ****
/* Average number of executed insns per iteration. */
unsigned av_ninsns;
- /* The first block in the loop. This is not necessarily the same as
- the loop header. */
- basic_block first;
-
- /* The last block in the loop. This is not necessarily the same as
- the loop latch. */
- basic_block last;
-
/* Number of blocks contained within the loop. */
unsigned num_nodes;
--- 78,83 ----
*************** struct loop
*** 111,156 ****
/* Loop that is copy of this loop. */
struct loop *copy;
- /* Nonzero if the loop is invalid (e.g., contains setjmp.). */
- int invalid;
-
/* Auxiliary info specific to a pass. */
void *aux;
- /* The following are currently used by loop.c but they are likely to
- disappear when loop.c is replaced and removed. */
-
- /* The NOTE_INSN_LOOP_BEG. */
- rtx start;
-
- /* The NOTE_INSN_LOOP_END. */
- rtx end;
-
- /* For a rotated loop that is entered near the bottom,
- this is the label at the top. Otherwise it is zero. */
- rtx top;
-
- /* Place in the loop where control enters. */
- rtx scan_start;
-
- /* The position where to sink insns out of the loop. */
- rtx sink;
-
- /* List of all LABEL_REFs which refer to code labels outside the
- loop. Used by routines that need to know all loop exits, such as
- final_biv_value and final_giv_value.
-
- This does not include loop exits due to return instructions.
- This is because all bivs and givs are pseudos, and hence must be
- dead after a return, so the presence of a return does not affect
- any of the optimizations that use this info. It is simpler to
- just not include return instructions on this list. */
- rtx exit_labels;
-
- /* The number of LABEL_REFs on exit_labels for this loop and all
- loops nested inside it. */
- int exit_count;
-
/* The probable number of times the loop is executed at runtime.
This is an INTEGER_CST or an expression containing symbolic
names. Don't access this field directly:
--- 103,111 ----
*************** int flow_loop_nodes_find (basic_block, s
*** 243,249 ****
void fix_loop_structure (struct loops *, bitmap changed_bbs);
void mark_irreducible_loops (struct loops *);
void mark_single_exit_loops (struct loops *);
- extern void create_loop_notes (void);
/* Loop data structure manipulation/querying. */
extern void flow_loop_tree_node_add (struct loop *, struct loop *);
--- 198,203 ----
Index: config/sh/sh.c
===================================================================
*** config/sh/sh.c (revision 111675)
--- config/sh/sh.c (working copy)
*************** static bool unspec_caller_rtx_p (rtx);
*** 241,249 ****
static bool sh_cannot_copy_insn_p (rtx);
static bool sh_rtx_costs (rtx, int, int, int *);
static int sh_address_cost (rtx);
- #ifdef TARGET_ADJUST_UNROLL_MAX
- static int sh_adjust_unroll_max (struct loop *, int, int, int, int);
- #endif
static int sh_pr_n_sets (void);
static rtx sh_allocate_initial_value (rtx);
static int shmedia_target_regs_stack_space (HARD_REG_SET *);
--- 241,246 ----
*************** static int hard_regs_intersect_p (HARD_R
*** 468,478 ****
#endif /* SYMBIAN */
- #ifdef TARGET_ADJUST_UNROLL_MAX
- #undef TARGET_ADJUST_UNROLL_MAX
- #define TARGET_ADJUST_UNROLL_MAX sh_adjust_unroll_max
- #endif
-
#undef TARGET_SECONDARY_RELOAD
#define TARGET_SECONDARY_RELOAD sh_secondary_reload
--- 465,470 ----
*************** static bool
*** 8906,8912 ****
sh_optimize_target_register_callee_saved (bool after_prologue_epilogue_gen)
{
HARD_REG_SET dummy;
- rtx insn;
if (! shmedia_space_reserved_for_target_registers)
return 0;
--- 8898,8903 ----
*************** sh_optimize_target_register_callee_saved
*** 8914,8941 ****
return 0;
if (calc_live_regs (&dummy) >= 6 * 8)
return 1;
- /* This is a borderline case. See if we got a nested loop, or a loop
- with a call, or with more than 4 labels inside. */
- for (insn = get_insns(); insn; insn = NEXT_INSN (insn))
- {
- if (GET_CODE (insn) == NOTE
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
- {
- int labels = 0;
-
- do
- {
- insn = NEXT_INSN (insn);
- if ((GET_CODE (insn) == NOTE
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
- || GET_CODE (insn) == CALL_INSN
- || (GET_CODE (insn) == CODE_LABEL && ++labels > 4))
- return 1;
- }
- while (GET_CODE (insn) != NOTE
- || NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END);
- }
- }
return 0;
}
--- 8905,8910 ----
*************** hard_regs_intersect_p (HARD_REG_SET *a,
*** 10173,10447 ****
lose:
return 0;
}
-
- #ifdef TARGET_ADJUST_UNROLL_MAX
- static int
- sh_adjust_unroll_max (struct loop * loop, int insn_count,
- int max_unrolled_insns, int strength_reduce_p,
- int unroll_type)
- {
- /* This doesn't work in 4.0 because the old unroller & loop.h is gone. */
- if (TARGET_ADJUST_UNROLL && TARGET_SHMEDIA)
- {
- /* Throttle back loop unrolling so that the costs of using more
- targets than the eight target register we have don't outweigh
- the benefits of unrolling. */
- rtx insn;
- int n_labels = 0, n_calls = 0, n_exit_dest = 0, n_inner_loops = -1;
- int n_barriers = 0;
- rtx dest;
- int i;
- rtx exit_dest[8];
- int threshold;
- int unroll_benefit = 0, mem_latency = 0;
- int base_cost, best_cost, cost;
- int factor, best_factor;
- int n_dest;
- unsigned max_iterations = 32767;
- int n_iterations;
- int need_precond = 0, precond = 0;
- basic_block * bbs = get_loop_body (loop);
- struct niter_desc *desc;
-
- /* Assume that all labels inside the loop are used from inside the
- loop. If the loop has multiple entry points, it is unlikely to
- be unrolled anyways.
- Also assume that all calls are to different functions. That is
- somewhat pessimistic, but if you have lots of calls, unrolling the
- loop is not likely to gain you much in the first place. */
- i = loop->num_nodes - 1;
- for (insn = BB_HEAD (bbs[i]); ; )
- {
- if (GET_CODE (insn) == CODE_LABEL)
- n_labels++;
- else if (GET_CODE (insn) == CALL_INSN)
- n_calls++;
- else if (GET_CODE (insn) == NOTE
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
- n_inner_loops++;
- else if (GET_CODE (insn) == BARRIER)
- n_barriers++;
- if (insn != BB_END (bbs[i]))
- insn = NEXT_INSN (insn);
- else if (--i >= 0)
- insn = BB_HEAD (bbs[i]);
- else
- break;
- }
- free (bbs);
- /* One label for the loop top is normal, and it won't be duplicated by
- unrolling. */
- if (n_labels <= 1)
- return max_unrolled_insns;
- if (n_inner_loops > 0)
- return 0;
- for (dest = loop->exit_labels; dest && n_exit_dest < 8;
- dest = LABEL_NEXTREF (dest))
- {
- for (i = n_exit_dest - 1;
- i >= 0 && XEXP (dest, 0) != XEXP (exit_dest[i], 0); i--);
- if (i < 0)
- exit_dest[n_exit_dest++] = dest;
- }
- /* If the loop top and call and exit destinations are enough to fill up
- the target registers, we're unlikely to do any more damage by
- unrolling. */
- if (n_calls + n_exit_dest >= 7)
- return max_unrolled_insns;
-
- /* ??? In the new loop unroller, there is no longer any strength
- reduction information available. Thus, when it comes to unrolling,
- we know the cost of everything, but we know the value of nothing. */
- #if 0
- if (strength_reduce_p
- && (unroll_type == LPT_UNROLL_RUNTIME
- || unroll_type == LPT_UNROLL_CONSTANT
- || unroll_type == LPT_PEEL_COMPLETELY))
- {
- struct loop_ivs *ivs = LOOP_IVS (loop);
- struct iv_class *bl;
-
- /* We'll save one compare-and-branch in each loop body copy
- but the last one. */
- unroll_benefit = 1;
- /* Assess the benefit of removing biv & giv updates. */
- for (bl = ivs->list; bl; bl = bl->next)
- {
- rtx increment = biv_total_increment (bl);
- struct induction *v;
-
- if (increment && GET_CODE (increment) == CONST_INT)
- {
- unroll_benefit++;
- for (v = bl->giv; v; v = v->next_iv)
- {
- if (! v->ignore && v->same == 0
- && GET_CODE (v->mult_val) == CONST_INT)
- unroll_benefit++;
- /* If this giv uses an array, try to determine
- a maximum iteration count from the size of the
- array. This need not be correct all the time,
- but should not be too far off the mark too often. */
- while (v->giv_type == DEST_ADDR)
- {
- rtx mem = PATTERN (v->insn);
- tree mem_expr, type, size_tree;
-
- if (GET_CODE (SET_SRC (mem)) == MEM)
- mem = SET_SRC (mem);
- else if (GET_CODE (SET_DEST (mem)) == MEM)
- mem = SET_DEST (mem);
- else
- break;
- mem_expr = MEM_EXPR (mem);
- if (! mem_expr)
- break;
- type = TREE_TYPE (mem_expr);
- if (TREE_CODE (type) != ARRAY_TYPE
- || ! TYPE_SIZE (type) || ! TYPE_SIZE_UNIT (type))
- break;
- size_tree = fold_build2 (TRUNC_DIV_EXPR,
- bitsizetype,
- TYPE_SIZE (type),
- TYPE_SIZE_UNIT (type));
- if (TREE_CODE (size_tree) == INTEGER_CST
- && ! TREE_INT_CST_HIGH (size_tree)
- && TREE_INT_CST_LOW (size_tree) < max_iterations)
- max_iterations = TREE_INT_CST_LOW (size_tree);
- break;
- }
- }
- }
- }
- }
- #else /* 0 */
- /* Assume there is at least some benefit. */
- unroll_benefit = 1;
- #endif /* 0 */
-
- desc = get_simple_loop_desc (loop);
- n_iterations = desc->const_iter ? desc->niter : 0;
- max_iterations
- = max_iterations < desc->niter_max ? max_iterations : desc->niter_max;
-
- if (! strength_reduce_p || ! n_iterations)
- need_precond = 1;
- if (! n_iterations)
- {
- n_iterations
- = max_iterations < 3 ? max_iterations : max_iterations * 3 / 4;
- if (! n_iterations)
- return 0;
- }
- #if 0 /* ??? See above - missing induction variable information. */
- while (unroll_benefit > 1) /* no loop */
- {
- /* We include the benefit of biv/ giv updates. Check if some or
- all of these updates are likely to fit into a scheduling
- bubble of a load.
- We check for the following case:
- - All the insns leading to the first JUMP_INSN are in a strict
- dependency chain.
- - there is at least one memory reference in them.
-
- When we find such a pattern, we assume that we can hide as many
- updates as the total of the load latency is, if we have an
- unroll factor of at least two. We might or might not also do
- this without unrolling, so rather than considering this as an
- extra unroll benefit, discount it in the unroll benefits of unroll
- factors higher than two. */
-
- rtx set, last_set;
-
- insn = next_active_insn (loop->start);
- last_set = single_set (insn);
- if (! last_set)
- break;
- if (GET_CODE (SET_SRC (last_set)) == MEM)
- mem_latency += 2;
- for (insn = NEXT_INSN (insn); insn != end; insn = NEXT_INSN (insn))
- {
- if (! INSN_P (insn))
- continue;
- if (GET_CODE (insn) == JUMP_INSN)
- break;
- if (! reg_referenced_p (SET_DEST (last_set), PATTERN (insn)))
- {
- /* Check if this is a to-be-reduced giv insn. */
- struct loop_ivs *ivs = LOOP_IVS (loop);
- struct iv_class *bl;
- struct induction *v;
- for (bl = ivs->list; bl; bl = bl->next)
- {
- if (bl->biv->insn == insn)
- goto is_biv;
- for (v = bl->giv; v; v = v->next_iv)
- if (v->insn == insn)
- goto is_giv;
- }
- mem_latency--;
- is_biv:
- is_giv:
- continue;
- }
- set = single_set (insn);
- if (! set)
- continue;
- if (GET_CODE (SET_SRC (set)) == MEM)
- mem_latency += 2;
- last_set = set;
- }
- if (mem_latency < 0)
- mem_latency = 0;
- else if (mem_latency > unroll_benefit - 1)
- mem_latency = unroll_benefit - 1;
- break;
- }
- #endif /* 0 */
- if (n_labels + (unroll_benefit + n_labels * 8) / n_iterations
- <= unroll_benefit)
- return max_unrolled_insns;
-
- n_dest = n_labels + n_calls + n_exit_dest;
- base_cost = n_dest <= 8 ? 0 : n_dest - 7;
- best_cost = 0;
- best_factor = 1;
- if (n_barriers * 2 > n_labels - 1)
- n_barriers = (n_labels - 1) / 2;
- for (factor = 2; factor <= 8; factor++)
- {
- /* Bump up preconditioning cost for each power of two. */
- if (! (factor & (factor-1)))
- precond += 4;
- /* When preconditioning, only powers of two will be considered. */
- else if (need_precond)
- continue;
- n_dest = ((unroll_type != LPT_PEEL_COMPLETELY)
- + (n_labels - 1) * factor + n_calls + n_exit_dest
- - (n_barriers * factor >> 1)
- + need_precond);
- cost
- = ((n_dest <= 8 ? 0 : n_dest - 7)
- - base_cost * factor
- - ((factor > 2 ? unroll_benefit - mem_latency : unroll_benefit)
- * (factor - (unroll_type != LPT_PEEL_COMPLETELY)))
- + ((unroll_benefit + 1 + (n_labels - 1) * factor)
- / n_iterations));
- if (need_precond)
- cost += (precond + unroll_benefit * factor / 2) / n_iterations;
- if (cost < best_cost)
- {
- best_cost = cost;
- best_factor = factor;
- }
- }
- threshold = best_factor * insn_count;
- if (max_unrolled_insns > threshold)
- max_unrolled_insns = threshold;
- }
- return max_unrolled_insns;
- }
- #endif /* TARGET_ADJUST_UNROLL_MAX */
/* Replace any occurrence of FROM(n) in X with TO(n). The function does
not enter into CONST_DOUBLE for the replace.
--- 10142,10147 ----
Index: cfgrtl.c
===================================================================
*** cfgrtl.c (revision 111675)
--- cfgrtl.c (working copy)
*************** Software Foundation, 51 Franklin Street,
*** 64,71 ****
static int can_delete_note_p (rtx);
static int can_delete_label_p (rtx);
static void commit_one_edge_insertion (edge, int);
- static rtx last_loop_beg_note (rtx);
- static bool back_edge_of_syntactic_loop_p (basic_block, basic_block);
static basic_block rtl_split_edge (edge);
static bool rtl_move_block_after (basic_block, basic_block);
static int rtl_verify_flow_info (void);
--- 64,69 ----
*************** try_redirect_by_replacing_jump (edge e,
*** 861,888 ****
return e;
}
- /* Return last loop_beg note appearing after INSN, before start of next
- basic block. Return INSN if there are no such notes.
-
- When emitting jump to redirect a fallthru edge, it should always appear
- after the LOOP_BEG notes, as loop optimizer expect loop to either start by
- fallthru edge or jump following the LOOP_BEG note jumping to the loop exit
- test. */
-
- static rtx
- last_loop_beg_note (rtx insn)
- {
- rtx last = insn;
-
- for (insn = NEXT_INSN (insn); insn && NOTE_P (insn)
- && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK;
- insn = NEXT_INSN (insn))
- if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
- last = insn;
-
- return last;
- }
-
/* Redirect edge representing branch of (un)conditional jump or tablejump,
NULL on failure */
static edge
--- 859,864 ----
*************** force_nonfallthru_and_redirect (edge e,
*** 1100,1108 ****
forward from the last instruction of the old block. */
if (!tablejump_p (BB_END (e->src), NULL, ¬e))
note = BB_END (e->src);
-
- /* Position the new block correctly relative to loop notes. */
- note = last_loop_beg_note (note);
note = NEXT_INSN (note);
jump_block = create_basic_block (note, NULL, e->src);
--- 1076,1081 ----
*************** rtl_tidy_fallthru_edge (edge e)
*** 1254,1293 ****
e->flags |= EDGE_FALLTHRU;
}
- /* Helper function for split_edge. Return true in case edge BB2 to BB1
- is back edge of syntactic loop. */
-
- static bool
- back_edge_of_syntactic_loop_p (basic_block bb1, basic_block bb2)
- {
- rtx insn;
- int count = 0;
- basic_block bb;
-
- if (bb1 == bb2)
- return true;
-
- /* ??? Could we guarantee that bb indices are monotone, so that we could
- just compare them? */
- for (bb = bb1; bb && bb != bb2; bb = bb->next_bb)
- continue;
-
- if (!bb)
- return false;
-
- for (insn = BB_END (bb1); insn != BB_HEAD (bb2) && count >= 0;
- insn = NEXT_INSN (insn))
- if (NOTE_P (insn))
- {
- if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
- count++;
- else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
- count--;
- }
-
- return count >= 0;
- }
-
/* Should move basic block BB after basic block AFTER. NIY. */
static bool
--- 1227,1232 ----
*************** rtl_split_edge (edge edge_in)
*** 1328,1359 ****
force_nonfallthru (e);
}
! /* Create the basic block note.
!
! Where we place the note can have a noticeable impact on the generated
! code. Consider this cfg:
!
! E
! |
! 0
! / \
! +->1-->2--->E
! | |
! +--+
!
! If we need to insert an insn on the edge from block 0 to block 1,
! we want to ensure the instructions we insert are outside of any
! loop notes that physically sit between block 0 and block 1. Otherwise
! we confuse the loop optimizer into thinking the loop is a phony. */
!
! if (edge_in->dest != EXIT_BLOCK_PTR
! && PREV_INSN (BB_HEAD (edge_in->dest))
! && NOTE_P (PREV_INSN (BB_HEAD (edge_in->dest)))
! && (NOTE_LINE_NUMBER (PREV_INSN (BB_HEAD (edge_in->dest)))
! == NOTE_INSN_LOOP_BEG)
! && !back_edge_of_syntactic_loop_p (edge_in->dest, edge_in->src))
! before = PREV_INSN (BB_HEAD (edge_in->dest));
! else if (edge_in->dest != EXIT_BLOCK_PTR)
before = BB_HEAD (edge_in->dest);
else
before = NULL_RTX;
--- 1267,1274 ----
force_nonfallthru (e);
}
! /* Create the basic block note. */
! if (edge_in->dest != EXIT_BLOCK_PTR)
before = BB_HEAD (edge_in->dest);
else
before = NULL_RTX;
*************** rtl_split_edge (edge edge_in)
*** 1363,1372 ****
if (edge_in->flags & EDGE_FALLTHRU && edge_in->dest == EXIT_BLOCK_PTR)
{
before = NEXT_INSN (BB_END (edge_in->src));
- if (before
- && NOTE_P (before)
- && NOTE_LINE_NUMBER (before) == NOTE_INSN_LOOP_END)
- before = NEXT_INSN (before);
bb = create_basic_block (before, NULL, edge_in->src);
BB_COPY_PARTITION (bb, edge_in->src);
}
--- 1278,1283 ----
*************** commit_one_edge_insertion (edge e, int w
*** 1596,1606 ****
We know this block has a single successor, so we can just emit
the queued insns before the jump. */
if (JUMP_P (BB_END (bb)))
! for (before = BB_END (bb);
! NOTE_P (PREV_INSN (before))
! && NOTE_LINE_NUMBER (PREV_INSN (before)) ==
! NOTE_INSN_LOOP_BEG; before = PREV_INSN (before))
! ;
else
{
/* We'd better be fallthru, or we've lost track of
--- 1507,1513 ----
We know this block has a single successor, so we can just emit
the queued insns before the jump. */
if (JUMP_P (BB_END (bb)))
! before = BB_END (bb);
else
{
/* We'd better be fallthru, or we've lost track of