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)
of an insn added during loop, since these don't have LUIDs. */
#define INSN_LUID(INSN) \
- (INSN_UID (INSN) < max_uid_for_loop ? uid_luid[INSN_UID (INSN)] \
- : (abort (), -1))
+ (gcc_assert (INSN_UID (INSN) < max_uid_for_loop), uid_luid[INSN_UID (INSN)])
#define REGNO_FIRST_LUID(REGNO) \
(REGNO_FIRST_UID (REGNO) < max_uid_for_loop \
#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.
/* See if we went too far. Note that get_max_uid already returns
one more that the maximum uid of all insn. */
- if (get_max_uid () > max_uid_for_loop)
- abort ();
+ gcc_assert (get_max_uid () <= max_uid_for_loop);
/* Now reset it to the actual size we need. See above. */
max_uid_for_loop = get_max_uid ();
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
contain anything but integers and other rtx's,
except for within LABEL_REFs and SYMBOL_REFs. */
default:
- abort ();
+ gcc_unreachable ();
}
}
return 1;
for (count = m->consec; count >= 0; count--)
{
- /* If this is the first insn of a library call sequence,
- something is very wrong. */
- if (!NOTE_P (p)
- && (temp = find_reg_note (p, REG_LIBCALL, NULL_RTX)))
- abort ();
-
- /* If this is the last insn of a libcall sequence, then
- delete every insn in the sequence except the last.
- The last insn is handled in the normal manner. */
- if (!NOTE_P (p)
- && (temp = find_reg_note (p, REG_RETVAL, NULL_RTX)))
+ if (!NOTE_P (p))
{
- temp = XEXP (temp, 0);
- while (temp != p)
- temp = delete_insn (temp);
+ /* If this is the first insn of a library
+ call sequence, something is very
+ wrong. */
+ gcc_assert (!find_reg_note
+ (p, REG_LIBCALL, NULL_RTX));
+
+ /* If this is the last insn of a libcall
+ sequence, then delete every insn in the
+ sequence except the last. The last insn
+ is handled in the normal manner. */
+ temp = find_reg_note (p, REG_RETVAL, NULL_RTX);
+
+ if (temp)
+ {
+ temp = XEXP (temp, 0);
+ while (temp != p)
+ temp = delete_insn (temp);
+ }
}
temp = p;
<< GET_MODE_BITSIZE (m->savemode)))
- 1),
reg, 1, OPTAB_LIB_WIDEN);
- if (tem == 0)
- abort ();
+ gcc_assert (tem);
if (tem != reg)
emit_move_insn (reg, tem);
sequence = get_insns ();
case MEM:
/* If this MEM uses a reg other than the one we expected,
something is wrong. */
- if (XEXP (x, 0) != reg)
- abort ();
+ gcc_assert (XEXP (x, 0) == reg);
XEXP (x, 0) = addr;
return;
break;
case NOTE_INSN_LOOP_END:
- if (! current_loop)
- abort ();
+ gcc_assert (current_loop);
current_loop->end = insn;
current_loop = current_loop->outer;
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. */
/* If we didn't find it, then something is
wrong. */
- if (! r)
- abort ();
+ gcc_assert (r);
}
/* P is now a jump outside the loop, so it must be put
contain anything but integers and other rtx's,
except for within LABEL_REFs and SYMBOL_REFs. */
default:
- abort ();
+ gcc_unreachable ();
}
}
return 1;
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;
/* The modes must all be the same. This should always be true. For now,
check to make sure. */
- if ((GET_MODE (mult1) != mode && GET_MODE (mult1) != VOIDmode)
- || (GET_MODE (mult2) != mode && GET_MODE (mult2) != VOIDmode)
- || (GET_MODE (add1) != mode && GET_MODE (add1) != VOIDmode))
- abort ();
+ gcc_assert (GET_MODE (mult1) == mode || GET_MODE (mult1) == VOIDmode);
+ gcc_assert (GET_MODE (mult2) == mode || GET_MODE (mult2) == VOIDmode);
+ gcc_assert (GET_MODE (add1) == mode || GET_MODE (add1) == VOIDmode);
/* Ensure that if at least one of mult1/mult2 are constant, then mult2
will be a constant. */
/* 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))
+ && CONSTANT_P (XEXP (*v->location, 1)))
+ {
+ rtx tem;
+ start_sequence ();
+ tem = expand_simple_binop (GET_MODE (*v->location), MINUS,
+ v->new_reg, XEXP (*v->location, 1),
+ NULL_RTX, 0, OPTAB_LIB_WIDEN);
+ emit_move_insn (XEXP (*v->location, 0), tem);
+ tem = get_insns ();
+ end_sequence ();
+ loop_insn_emit_before (loop, 0, v->insn, tem);
+ }
+ 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;
will propagate a new pseudo into the old iteration register but
this will be marked by having the REG_USERVAR_P bit set. */
- if ((unsigned) REGNO (iteration_var) >= ivs->n_regs
- && ! REG_USERVAR_P (iteration_var))
- abort ();
+ gcc_assert ((unsigned) REGNO (iteration_var) < ivs->n_regs
+ || REG_USERVAR_P (iteration_var));
/* Determine the initial value of the iteration variable, and the amount
that it is incremented each loop. Use the tables constructed by
if (REG_IV_TYPE (ivs, REGNO (iteration_var)) == BASIC_INDUCT)
{
- if (REGNO (iteration_var) >= ivs->n_regs)
- abort ();
+ gcc_assert (REGNO (iteration_var) < ivs->n_regs);
/* Grab initial value, only useful if it is a constant. */
bl = REG_IV_CLASS (ivs, REGNO (iteration_var));
struct induction *v = REG_IV_INFO (ivs, REGNO (iteration_var));
rtx biv_initial_value;
- if (REGNO (v->src_reg) >= ivs->n_regs)
- abort ();
+ gcc_assert (REGNO (v->src_reg) < ivs->n_regs);
if (!v->always_executed || v->maybe_multiple)
{
compare_dir = 0;
break;
default:
- abort ();
+ gcc_unreachable ();
}
/* If the comparison value is an invariant register, then try to find
unsigned, because they can be as large as 2^n - 1. */
inc = INTVAL (increment);
+ gcc_assert (inc);
if (inc > 0)
{
abs_diff = INTVAL (final_value) - INTVAL (initial_value);
abs_inc = inc;
}
- else if (inc < 0)
+ else
{
abs_diff = INTVAL (initial_value) - INTVAL (final_value);
abs_inc = -inc;
}
- else
- abort ();
/* Given that iteration_var is going to iterate over its own mode,
not HOST_WIDE_INT, disregard higher bits that might have come
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
/* Add the giv to the class of givs computed from one biv. */
bl = REG_IV_CLASS (ivs, REGNO (src_reg));
- if (bl)
- {
- v->next_iv = bl->giv;
- bl->giv = v;
- /* Don't count DEST_ADDR. This is supposed to count the number of
- insns that calculate givs. */
- if (type == DEST_REG)
- bl->giv_count++;
- bl->total_benefit += benefit;
- }
- else
- /* Fatal error, biv missing for this giv? */
- abort ();
+ gcc_assert (bl);
+ v->next_iv = bl->giv;
+ bl->giv = v;
+
+ /* Don't count DEST_ADDR. This is supposed to count the number of
+ insns that calculate givs. */
+ if (type == DEST_REG)
+ bl->giv_count++;
+ bl->total_benefit += benefit;
if (type == DEST_ADDR)
{
}
/* Replaceable giv's should never reach here. */
- if (v->replaceable)
- abort ();
+ gcc_assert (!v->replaceable);
/* Check to see if the biv is dead at all loop exits. */
if (reg_dead_after_loop (loop, v->dest_reg))
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))
break;
default:
- abort ();
+ gcc_unreachable ();
}
/* Remove any enclosing USE from ADD_VAL and MULT_VAL (there will be
ext_val, benefit);
default:
- abort ();
+ gcc_unreachable ();
}
/* Each argument must be either REG, PLUS, or MULT. Convert REG to
ext_val, benefit);
default:
- abort ();
+ gcc_unreachable ();
}
case ASHIFT:
break;
default:
- abort ();
+ gcc_unreachable ();
}
return ((!signedp || biv_fits_mode_p (loop, bl, incr, mode, false))
/* If a DEST_REG GIV is used only once, do not allow it to combine
with anything, for in doing so we will gain nothing that cannot
be had by simply letting the GIV with which we would have combined
- to be reduced on its own. The losage shows up in particular with
+ to be reduced on its own. The lossage shows up in particular with
DEST_ADDR targets on hosts with reg+reg addressing, though it can
be seen elsewhere as well. */
if (g1->giv_type == DEST_REG
&& REG_P (SET_DEST (set))
&& REGNO (SET_DEST (set)) == regno)
{
- if (init_insn)
- abort ();
+ gcc_assert (!init_insn);
init_insn = insn;
if (REGNO_FIRST_UID (regno) == INSN_UID (insn))
}
}
}
- if (! init_insn)
- abort ();
+ gcc_assert (init_insn);
if (apply_change_group ())
{
if (loop_dump_stream)
fprintf (file, " ext tr");
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
{
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 */
+};
+
+