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