You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* This is the loop optimization pass of the compiler.
It finds invariant computations within loops and moves them
#include "optabs.h"
#include "cfgloop.h"
#include "ggc.h"
+#include "timevar.h"
+#include "tree-pass.h"
/* Get the loop info pointer of a loop. */
#define LOOP_INFO(LOOP) ((struct loop_info *) (LOOP)->aux)
#ifndef HAVE_prefetch
#define HAVE_prefetch 0
#define CODE_FOR_prefetch 0
-#define gen_prefetch(a,b,c) (abort(), NULL_RTX)
+#define gen_prefetch(a,b,c) (gcc_unreachable (), NULL_RTX)
#endif
/* Give up the prefetch optimizations once we exceed a given threshold.
if (! in_libcall
&& (set = single_set (p))
&& REG_P (SET_DEST (set))
+ && SET_DEST (set) != frame_pointer_rtx
#ifdef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
&& SET_DEST (set) != pic_offset_table_rtx
#endif
if (invert_jump (p, new_label, 1))
{
rtx q, r;
+ bool only_notes;
/* If no suitable BARRIER was found, create a suitable
one before TARGET. Since TARGET is a fall through
/* Include the BARRIER after INSN and copy the
block after LOC. */
- if (squeeze_notes (&new_label, &last_insn_to_move))
- abort ();
+ only_notes = squeeze_notes (&new_label,
+ &last_insn_to_move);
+ gcc_assert (!only_notes);
+
reorder_insns (new_label, last_insn_to_move, loc);
/* All those insns are now in TARGET_LOOP. */
int not_every_iteration = 0;
int maybe_multiple = 0;
int past_loop_latch = 0;
+ bool exit_test_is_entry = false;
rtx p;
- /* If loop_scan_start points to the loop exit test, we have to be wary of
- subversive use of gotos inside expression statements. */
+ /* If loop_scan_start points to the loop exit test, the loop body
+ cannot be counted on running on every iteration, and we have to
+ be wary of subversive use of gotos inside expression
+ statements. */
if (prev_nonnote_insn (loop->scan_start) != prev_nonnote_insn (loop->start))
- maybe_multiple = back_branch_in_range_p (loop, loop->scan_start);
+ {
+ exit_test_is_entry = true;
+ maybe_multiple = back_branch_in_range_p (loop, loop->scan_start);
+ }
/* Scan through loop and update NOT_EVERY_ITERATION and MAYBE_MULTIPLE. */
for (p = next_insn_in_loop (loop, loop->scan_start);
beginning, don't set not_every_iteration for that.
This can be any kind of jump, since we want to know if insns
will be executed if the loop is executed. */
- && !(JUMP_LABEL (p) == loop->top
- && ((NEXT_INSN (NEXT_INSN (p)) == loop->end
- && any_uncondjump_p (p))
- || (NEXT_INSN (p) == loop->end && any_condjump_p (p)))))
+ && (exit_test_is_entry
+ || !(JUMP_LABEL (p) == loop->top
+ && ((NEXT_INSN (NEXT_INSN (p)) == loop->end
+ && any_uncondjump_p (p))
+ || (NEXT_INSN (p) == loop->end
+ && any_condjump_p (p))))))
{
rtx label = 0;
/* HACK: Must also search the loop fall through exit, create a label_ref
here which points to the loop->end, and append the loop_number_exit_labels
list to it. */
- label = gen_rtx_LABEL_REF (VOIDmode, loop->end);
+ label = gen_rtx_LABEL_REF (Pmode, loop->end);
LABEL_NEXTREF (label) = loop->exit_labels;
for (; label; label = LABEL_NEXTREF (label))
mark_reg_pointer (v->new_reg, 0);
if (v->giv_type == DEST_ADDR)
- /* Store reduced reg as the address in the memref where we found
- this giv. */
- validate_change (v->insn, v->location, v->new_reg, 0);
+ {
+ /* Store reduced reg as the address in the memref where we found
+ this giv. */
+ if (validate_change_maybe_volatile (v->insn, v->location,
+ v->new_reg))
+ /* Yay, it worked! */;
+ /* Not replaceable; emit an insn to set the original
+ giv reg from the reduced giv. */
+ else if (REG_P (*v->location))
+ loop_insn_emit_before (loop, 0, v->insn,
+ gen_move_insn (*v->location,
+ v->new_reg));
+ else if (GET_CODE (*v->location) == PLUS
+ && REG_P (XEXP (*v->location, 0))
+ && REG_P (v->new_reg)
+ && CONSTANT_P (XEXP (*v->location, 1)))
+ loop_insn_emit_before (loop, 0, v->insn,
+ gen_move_insn (XEXP (*v->location, 0),
+ gen_rtx_MINUS
+ (GET_MODE (*v->location),
+ v->new_reg,
+ XEXP (*v->location, 1))));
+ else
+ {
+ /* If it wasn't a reg, create a pseudo and use that. */
+ rtx reg, seq;
+ start_sequence ();
+ reg = force_reg (v->mode, *v->location);
+ seq = get_insns ();
+ end_sequence ();
+ loop_insn_emit_before (loop, 0, v->insn, seq);
+ if (!validate_change_maybe_volatile (v->insn, v->location, reg))
+ gcc_unreachable ();
+ }
+ }
else if (v->replaceable)
{
reg_map[REGNO (v->dest_reg)] = v->new_reg;
some machines, don't use any hard registers at all. */
if (REGNO (x) < FIRST_PSEUDO_REGISTER
&& (SMALL_REGISTER_CLASSES
- || (call_used_regs[REGNO (x)] && call_seen)))
+ || (call_seen && call_used_regs[REGNO (x)])))
return 0;
/* Don't use registers that have been clobbered before the start of the
case CONST_INT:
case SYMBOL_REF:
case CONST:
- /* convert_modes aborts if we try to convert to or from CCmode, so just
+ /* convert_modes dies if we try to convert to or from CCmode, so just
exclude that case. It is very unlikely that a condition code value
- would be a useful iterator anyways. convert_modes aborts if we try to
+ would be a useful iterator anyways. convert_modes dies if we try to
convert a float mode to non-float or vice versa too. */
if (loop->level == 1
&& GET_MODE_CLASS (mode) == GET_MODE_CLASS (GET_MODE (dest_reg))
{
flow_loops_dump (loops, stderr, loop_dump_aux, 1);
}
+\f
+static bool
+gate_handle_loop_optimize (void)
+{
+ return (optimize > 0 && flag_loop_optimize);
+}
+
+/* Move constant computations out of loops. */
+static void
+rest_of_handle_loop_optimize (void)
+{
+ int do_prefetch;
+
+ /* CFG is no longer maintained up-to-date. */
+ free_bb_for_insn ();
+ profile_status = PROFILE_ABSENT;
+
+ do_prefetch = flag_prefetch_loop_arrays ? LOOP_PREFETCH : 0;
+
+ if (flag_rerun_loop_opt)
+ {
+ cleanup_barriers ();
+
+ /* We only want to perform unrolling once. */
+ loop_optimize (get_insns (), dump_file, 0);
+
+ /* The first call to loop_optimize makes some instructions
+ trivially dead. We delete those instructions now in the
+ hope that doing so will make the heuristics in loop work
+ better and possibly speed up compilation. */
+ delete_trivially_dead_insns (get_insns (), max_reg_num ());
+
+ /* The regscan pass is currently necessary as the alias
+ analysis code depends on this information. */
+ reg_scan (get_insns (), max_reg_num ());
+ }
+ cleanup_barriers ();
+ loop_optimize (get_insns (), dump_file, do_prefetch);
+
+ /* Loop can create trivially dead instructions. */
+ delete_trivially_dead_insns (get_insns (), max_reg_num ());
+ find_basic_blocks (get_insns ());
+}
+
+struct tree_opt_pass pass_loop_optimize =
+{
+ "old-loop", /* name */
+ gate_handle_loop_optimize, /* gate */
+ rest_of_handle_loop_optimize, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_LOOP, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func |
+ TODO_ggc_collect, /* todo_flags_finish */
+ 'L' /* letter */
+};
+
+