#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "rtl.h"
+#include "rtl-error.h"
#include "tm_p.h"
#include "insn-config.h"
#include "insn-attr.h"
#include "expr.h"
#include "function.h"
#include "flags.h"
-#include "real.h"
-#include "toplev.h"
#include "basic-block.h"
#include "output.h"
#include "reload.h"
/* Oops, the caller has made X no longer canonical.
Let's redo the changes in the correct order. */
rtx tem = XEXP (x, 0);
- validate_change (insn, &XEXP (x, 0), XEXP (x, 1), 1);
- validate_change (insn, &XEXP (x, 1), tem, 1);
+ validate_unshare_change (insn, &XEXP (x, 0), XEXP (x, 1), 1);
+ validate_unshare_change (insn, &XEXP (x, 1), tem, 1);
return true;
}
else
return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode
|| mode == VOIDmode)
&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
- && LEGITIMATE_CONSTANT_P (op));
+ && targetm.legitimate_constant_p (mode == VOIDmode
+ ? GET_MODE (op)
+ : mode, op));
/* Except for certain constants with VOIDmode, already checked for,
OP's mode must match MODE if MODE specifies a mode. */
&& (GET_MODE (op) == mode || mode == VOIDmode
|| GET_MODE (op) == VOIDmode)
&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
- && LEGITIMATE_CONSTANT_P (op));
+ && targetm.legitimate_constant_p (mode == VOIDmode
+ ? GET_MODE (op)
+ : mode, op));
}
/* Returns 1 if OP is an operand that is a CONST_INT. */
nonmemory_operand (rtx op, enum machine_mode mode)
{
if (CONSTANT_P (op))
- {
- /* Don't accept CONST_INT or anything similar
- if the caller wants something floating. */
- if (GET_MODE (op) == VOIDmode && mode != VOIDmode
- && GET_MODE_CLASS (mode) != MODE_INT
- && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
- return 0;
-
- if (CONST_INT_P (op)
- && mode != VOIDmode
- && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
- return 0;
-
- return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode
- || mode == VOIDmode)
- && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
- && LEGITIMATE_CONSTANT_P (op));
- }
+ return immediate_operand (op, mode);
if (GET_MODE (op) != mode && mode != VOIDmode)
return 0;
asm_operand_ok (rtx op, const char *constraint, const char **constraints)
{
int result = 0;
+#ifdef AUTO_INC_DEC
+ bool incdec_ok = false;
+#endif
/* Use constrain_operands after reload. */
gcc_assert (!reload_completed);
/* Empty constraint string is the same as "X,...,X", i.e. X for as
many alternatives as required to match the other operands. */
if (*constraint == '\0')
- return 1;
+ result = 1;
while (*constraint)
{
|| GET_CODE (XEXP (op, 0)) == PRE_DEC
|| GET_CODE (XEXP (op, 0)) == POST_DEC))
result = 1;
+#ifdef AUTO_INC_DEC
+ incdec_ok = true;
+#endif
break;
case '>':
|| GET_CODE (XEXP (op, 0)) == PRE_INC
|| GET_CODE (XEXP (op, 0)) == POST_INC))
result = 1;
+#ifdef AUTO_INC_DEC
+ incdec_ok = true;
+#endif
break;
case 'E':
return 0;
}
+#ifdef AUTO_INC_DEC
+ /* For operands without < or > constraints reject side-effects. */
+ if (!incdec_ok && result && MEM_P (op))
+ switch (GET_CODE (XEXP (op, 0)))
+ {
+ case PRE_INC:
+ case POST_INC:
+ case PRE_DEC:
+ case POST_DEC:
+ case PRE_MODIFY:
+ case POST_MODIFY:
+ return 0;
+ default:
+ break;
+ }
+#endif
+
return result;
}
\f
recog_data.n_operands = 0;
recog_data.n_alternatives = 0;
recog_data.n_dups = 0;
+ recog_data.is_asm = false;
switch (GET_CODE (body))
{
while (*p)
recog_data.n_alternatives += (*p++ == ',');
}
+ recog_data.is_asm = true;
break;
}
fatal_insn_not_found (insn);
= recog_data.operand[funny_match[funny_match_index].this_op];
}
+#ifdef AUTO_INC_DEC
+ /* For operands without < or > constraints reject side-effects. */
+ if (recog_data.is_asm)
+ {
+ for (opno = 0; opno < recog_data.n_operands; opno++)
+ if (MEM_P (recog_data.operand[opno]))
+ switch (GET_CODE (XEXP (recog_data.operand[opno], 0)))
+ {
+ case PRE_INC:
+ case POST_INC:
+ case PRE_DEC:
+ case POST_DEC:
+ case PRE_MODIFY:
+ case POST_MODIFY:
+ if (strchr (recog_data.constraints[opno], '<') == NULL
+ && strchr (recog_data.constraints[opno], '>')
+ == NULL)
+ return 0;
+ break;
+ default:
+ break;
+ }
+ }
+#endif
return 1;
}
}
return 0;
}
-/* Return 1 iff OPERAND (assumed to be a REG rtx)
+/* Return true iff OPERAND (assumed to be a REG rtx)
is a hard reg in class CLASS when its regno is offset by OFFSET
and changed to mode MODE.
If REG occupies multiple hard regs, all of them must be in CLASS. */
-int
-reg_fits_class_p (rtx operand, enum reg_class cl, int offset,
+bool
+reg_fits_class_p (const_rtx operand, reg_class_t cl, int offset,
enum machine_mode mode)
{
int regno = REGNO (operand);
if (cl == NO_REGS)
- return 0;
+ return false;
- return (regno < FIRST_PSEUDO_REGISTER
+ return (HARD_REGISTER_NUM_P (regno)
&& in_hard_reg_set_p (reg_class_contents[(int) cl],
mode, regno + offset));
}
}
else
{
- rtx last = split_insn (insn);
- if (last)
+ if (split_insn (insn))
{
- /* The split sequence may include barrier, but the
- BB boundary we are interested in will be set to
- previous one. */
-
- while (BARRIER_P (last))
- last = PREV_INSN (last);
SET_BIT (blocks, bb->index);
changed = true;
}
static struct peep2_insn_data peep2_insn_data[MAX_INSNS_PER_PEEP2 + 1];
static int peep2_current;
+
+static bool peep2_do_rebuild_jump_labels;
+static bool peep2_do_cleanup_cfg;
+
/* The number of instructions available to match a peep2. */
int peep2_current_count;
DF_LIVE_OUT for the block. */
#define PEEP2_EOB pc_rtx
+/* Wrap N to fit into the peep2_insn_data buffer. */
+
+static int
+peep2_buf_position (int n)
+{
+ if (n >= MAX_INSNS_PER_PEEP2 + 1)
+ n -= MAX_INSNS_PER_PEEP2 + 1;
+ return n;
+}
+
/* Return the Nth non-note insn after `current', or return NULL_RTX if it
does not exist. Used by the recognizer to find the next insn to match
in a multi-insn pattern. */
{
gcc_assert (n <= peep2_current_count);
- n += peep2_current;
- if (n >= MAX_INSNS_PER_PEEP2 + 1)
- n -= MAX_INSNS_PER_PEEP2 + 1;
+ n = peep2_buf_position (peep2_current + n);
return peep2_insn_data[n].insn;
}
{
gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1);
- ofs += peep2_current;
- if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
- ofs -= MAX_INSNS_PER_PEEP2 + 1;
+ ofs = peep2_buf_position (peep2_current + ofs);
gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX);
gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1);
- ofs += peep2_current;
- if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
- ofs -= MAX_INSNS_PER_PEEP2 + 1;
+ ofs = peep2_buf_position (peep2_current + ofs);
gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX);
gcc_assert (from < MAX_INSNS_PER_PEEP2 + 1);
gcc_assert (to < MAX_INSNS_PER_PEEP2 + 1);
- from += peep2_current;
- if (from >= MAX_INSNS_PER_PEEP2 + 1)
- from -= MAX_INSNS_PER_PEEP2 + 1;
- to += peep2_current;
- if (to >= MAX_INSNS_PER_PEEP2 + 1)
- to -= MAX_INSNS_PER_PEEP2 + 1;
+ from = peep2_buf_position (peep2_current + from);
+ to = peep2_buf_position (peep2_current + to);
gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
REG_SET_TO_HARD_REG_SET (live, peep2_insn_data[from].live_before);
{
HARD_REG_SET this_live;
- if (++from >= MAX_INSNS_PER_PEEP2 + 1)
- from = 0;
+ from = peep2_buf_position (from + 1);
gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
REG_SET_TO_HARD_REG_SET (this_live, peep2_insn_data[from].live_before);
IOR_HARD_REG_SET (live, this_live);
COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
}
+/* While scanning basic block BB, we found a match of length MATCH_LEN,
+ starting at INSN. Perform the replacement, removing the old insns and
+ replacing them with ATTEMPT. Returns the last insn emitted, or NULL
+ if the replacement is rejected. */
+
+static rtx
+peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
+{
+ int i;
+ rtx last, note, before_try, x;
+ rtx old_insn, new_insn;
+ bool was_call = false;
+
+ /* If we are splittind an RTX_FRAME_RELATED_P insn, do not allow it to
+ match more than one insn, or to be split into more than one insn. */
+ old_insn = peep2_insn_data[peep2_current].insn;
+ if (RTX_FRAME_RELATED_P (old_insn))
+ {
+ bool any_note = false;
+
+ if (match_len != 0)
+ return NULL;
+
+ /* Look for one "active" insn. I.e. ignore any "clobber" insns that
+ may be in the stream for the purpose of register allocation. */
+ if (active_insn_p (attempt))
+ new_insn = attempt;
+ else
+ new_insn = next_active_insn (attempt);
+ if (next_active_insn (new_insn))
+ return NULL;
+
+ /* We have a 1-1 replacement. Copy over any frame-related info. */
+ RTX_FRAME_RELATED_P (new_insn) = 1;
+
+ /* Allow the backend to fill in a note during the split. */
+ for (note = REG_NOTES (new_insn); note ; note = XEXP (note, 1))
+ switch (REG_NOTE_KIND (note))
+ {
+ case REG_FRAME_RELATED_EXPR:
+ case REG_CFA_DEF_CFA:
+ case REG_CFA_ADJUST_CFA:
+ case REG_CFA_OFFSET:
+ case REG_CFA_REGISTER:
+ case REG_CFA_EXPRESSION:
+ case REG_CFA_RESTORE:
+ case REG_CFA_SET_VDRAP:
+ any_note = true;
+ break;
+ default:
+ break;
+ }
+
+ /* If the backend didn't supply a note, copy one over. */
+ if (!any_note)
+ for (note = REG_NOTES (old_insn); note ; note = XEXP (note, 1))
+ switch (REG_NOTE_KIND (note))
+ {
+ case REG_FRAME_RELATED_EXPR:
+ case REG_CFA_DEF_CFA:
+ case REG_CFA_ADJUST_CFA:
+ case REG_CFA_OFFSET:
+ case REG_CFA_REGISTER:
+ case REG_CFA_EXPRESSION:
+ case REG_CFA_RESTORE:
+ case REG_CFA_SET_VDRAP:
+ add_reg_note (new_insn, REG_NOTE_KIND (note), XEXP (note, 0));
+ any_note = true;
+ break;
+ default:
+ break;
+ }
+
+ /* If there still isn't a note, make sure the unwind info sees the
+ same expression as before the split. */
+ if (!any_note)
+ {
+ rtx old_set, new_set;
+
+ /* The old insn had better have been simple, or annotated. */
+ old_set = single_set (old_insn);
+ gcc_assert (old_set != NULL);
+
+ new_set = single_set (new_insn);
+ if (!new_set || !rtx_equal_p (new_set, old_set))
+ add_reg_note (new_insn, REG_FRAME_RELATED_EXPR, old_set);
+ }
+
+ /* Copy prologue/epilogue status. This is required in order to keep
+ proper placement of EPILOGUE_BEG and the DW_CFA_remember_state. */
+ maybe_copy_prologue_epilogue_insn (old_insn, new_insn);
+ }
+
+ /* If we are splitting a CALL_INSN, look for the CALL_INSN
+ in SEQ and copy our CALL_INSN_FUNCTION_USAGE and other
+ cfg-related call notes. */
+ for (i = 0; i <= match_len; ++i)
+ {
+ int j;
+
+ j = peep2_buf_position (peep2_current + i);
+ old_insn = peep2_insn_data[j].insn;
+ if (!CALL_P (old_insn))
+ continue;
+ was_call = true;
+
+ new_insn = attempt;
+ while (new_insn != NULL_RTX)
+ {
+ if (CALL_P (new_insn))
+ break;
+ new_insn = NEXT_INSN (new_insn);
+ }
+
+ gcc_assert (new_insn != NULL_RTX);
+
+ CALL_INSN_FUNCTION_USAGE (new_insn)
+ = CALL_INSN_FUNCTION_USAGE (old_insn);
+
+ for (note = REG_NOTES (old_insn);
+ note;
+ note = XEXP (note, 1))
+ switch (REG_NOTE_KIND (note))
+ {
+ case REG_NORETURN:
+ case REG_SETJMP:
+ add_reg_note (new_insn, REG_NOTE_KIND (note),
+ XEXP (note, 0));
+ break;
+ default:
+ /* Discard all other reg notes. */
+ break;
+ }
+
+ /* Croak if there is another call in the sequence. */
+ while (++i <= match_len)
+ {
+ j = peep2_buf_position (peep2_current + i);
+ old_insn = peep2_insn_data[j].insn;
+ gcc_assert (!CALL_P (old_insn));
+ }
+ break;
+ }
+
+ i = peep2_buf_position (peep2_current + match_len);
+
+ note = find_reg_note (peep2_insn_data[i].insn, REG_EH_REGION, NULL_RTX);
+
+ /* Replace the old sequence with the new. */
+ last = emit_insn_after_setloc (attempt,
+ peep2_insn_data[i].insn,
+ INSN_LOCATOR (peep2_insn_data[i].insn));
+ before_try = PREV_INSN (insn);
+ delete_insn_chain (insn, peep2_insn_data[i].insn, false);
+
+ /* Re-insert the EH_REGION notes. */
+ if (note || (was_call && nonlocal_goto_handler_labels))
+ {
+ edge eh_edge;
+ edge_iterator ei;
+
+ FOR_EACH_EDGE (eh_edge, ei, bb->succs)
+ if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL))
+ break;
+
+ if (note)
+ copy_reg_eh_region_note_backward (note, last, before_try);
+
+ if (eh_edge)
+ for (x = last; x != before_try; x = PREV_INSN (x))
+ if (x != BB_END (bb)
+ && (can_throw_internal (x)
+ || can_nonlocal_goto (x)))
+ {
+ edge nfte, nehe;
+ int flags;
+
+ nfte = split_block (bb, x);
+ flags = (eh_edge->flags
+ & (EDGE_EH | EDGE_ABNORMAL));
+ if (CALL_P (x))
+ flags |= EDGE_ABNORMAL_CALL;
+ nehe = make_edge (nfte->src, eh_edge->dest,
+ flags);
+
+ nehe->probability = eh_edge->probability;
+ nfte->probability
+ = REG_BR_PROB_BASE - nehe->probability;
+
+ peep2_do_cleanup_cfg |= purge_dead_edges (nfte->dest);
+ bb = nfte->src;
+ eh_edge = nehe;
+ }
+
+ /* Converting possibly trapping insn to non-trapping is
+ possible. Zap dummy outgoing edges. */
+ peep2_do_cleanup_cfg |= purge_dead_edges (bb);
+ }
+
+ /* If we generated a jump instruction, it won't have
+ JUMP_LABEL set. Recompute after we're done. */
+ for (x = last; x != before_try; x = PREV_INSN (x))
+ if (JUMP_P (x))
+ {
+ peep2_do_rebuild_jump_labels = true;
+ break;
+ }
+
+ return last;
+}
+
+/* After performing a replacement in basic block BB, fix up the life
+ information in our buffer. LAST is the last of the insns that we
+ emitted as a replacement. PREV is the insn before the start of
+ the replacement. MATCH_LEN is the number of instructions that were
+ matched, and which now need to be replaced in the buffer. */
+
+static void
+peep2_update_life (basic_block bb, int match_len, rtx last, rtx prev)
+{
+ int i = peep2_buf_position (peep2_current + match_len + 1);
+ rtx x;
+ regset_head live;
+
+ INIT_REG_SET (&live);
+ COPY_REG_SET (&live, peep2_insn_data[i].live_before);
+
+ gcc_assert (peep2_current_count >= match_len + 1);
+ peep2_current_count -= match_len + 1;
+
+ x = last;
+ do
+ {
+ if (INSN_P (x))
+ {
+ df_insn_rescan (x);
+ if (peep2_current_count < MAX_INSNS_PER_PEEP2)
+ {
+ peep2_current_count++;
+ if (--i < 0)
+ i = MAX_INSNS_PER_PEEP2;
+ peep2_insn_data[i].insn = x;
+ df_simulate_one_insn_backwards (bb, x, &live);
+ COPY_REG_SET (peep2_insn_data[i].live_before, &live);
+ }
+ }
+ x = PREV_INSN (x);
+ }
+ while (x != prev);
+ CLEAR_REG_SET (&live);
+
+ peep2_current = i;
+}
+
+/* Add INSN, which is in BB, at the end of the peep2 insn buffer if possible.
+ Return true if we added it, false otherwise. The caller will try to match
+ peepholes against the buffer if we return false; otherwise it will try to
+ add more instructions to the buffer. */
+
+static bool
+peep2_fill_buffer (basic_block bb, rtx insn, regset live)
+{
+ int pos;
+
+ /* Once we have filled the maximum number of insns the buffer can hold,
+ allow the caller to match the insns against peepholes. We wait until
+ the buffer is full in case the target has similar peepholes of different
+ length; we always want to match the longest if possible. */
+ if (peep2_current_count == MAX_INSNS_PER_PEEP2)
+ return false;
+
+ /* If an insn has RTX_FRAME_RELATED_P set, do not allow it to be matched with
+ any other pattern, lest it change the semantics of the frame info. */
+ if (RTX_FRAME_RELATED_P (insn))
+ {
+ /* Let the buffer drain first. */
+ if (peep2_current_count > 0)
+ return false;
+ /* Now the insn will be the only thing in the buffer. */
+ }
+
+ pos = peep2_buf_position (peep2_current + peep2_current_count);
+ peep2_insn_data[pos].insn = insn;
+ COPY_REG_SET (peep2_insn_data[pos].live_before, live);
+ peep2_current_count++;
+
+ df_simulate_one_insn_forwards (bb, insn, live);
+ return true;
+}
+
/* Perform the peephole2 optimization pass. */
static void
peephole2_optimize (void)
{
- rtx insn, prev;
+ rtx insn;
bitmap live;
int i;
basic_block bb;
- bool do_cleanup_cfg = false;
- bool do_rebuild_jump_labels = false;
+
+ peep2_do_cleanup_cfg = false;
+ peep2_do_rebuild_jump_labels = false;
df_set_flags (DF_LR_RUN_DCE);
+ df_note_add_problem ();
df_analyze ();
/* Initialize the regsets we're going to use. */
FOR_EACH_BB_REVERSE (bb)
{
+ bool past_end = false;
+ int pos;
+
rtl_profile_for_bb (bb);
/* Start up propagation. */
- bitmap_copy (live, DF_LR_OUT (bb));
- df_simulate_initialize_backwards (bb, live);
+ bitmap_copy (live, DF_LR_IN (bb));
+ df_simulate_initialize_forwards (bb, live);
peep2_reinit_state (live);
- for (insn = BB_END (bb); ; insn = prev)
+ insn = BB_HEAD (bb);
+ for (;;)
{
- prev = PREV_INSN (insn);
- if (NONDEBUG_INSN_P (insn))
- {
- rtx attempt, before_try, x;
- int match_len;
- rtx note;
- bool was_call = false;
-
- /* Record this insn. */
- if (--peep2_current < 0)
- peep2_current = MAX_INSNS_PER_PEEP2;
- if (peep2_current_count < MAX_INSNS_PER_PEEP2
- && peep2_insn_data[peep2_current].insn == NULL_RTX)
- peep2_current_count++;
- peep2_insn_data[peep2_current].insn = insn;
- df_simulate_one_insn_backwards (bb, insn, live);
- COPY_REG_SET (peep2_insn_data[peep2_current].live_before, live);
-
- if (RTX_FRAME_RELATED_P (insn))
- {
- /* If an insn has RTX_FRAME_RELATED_P set, peephole
- substitution would lose the
- REG_FRAME_RELATED_EXPR that is attached. */
- peep2_reinit_state (live);
- attempt = NULL;
- }
- else
- /* Match the peephole. */
- attempt = peephole2_insns (PATTERN (insn), insn, &match_len);
-
- if (attempt != NULL)
- {
- /* If we are splitting a CALL_INSN, look for the CALL_INSN
- in SEQ and copy our CALL_INSN_FUNCTION_USAGE and other
- cfg-related call notes. */
- for (i = 0; i <= match_len; ++i)
- {
- int j;
- rtx old_insn, new_insn, note;
-
- j = i + peep2_current;
- if (j >= MAX_INSNS_PER_PEEP2 + 1)
- j -= MAX_INSNS_PER_PEEP2 + 1;
- old_insn = peep2_insn_data[j].insn;
- if (!CALL_P (old_insn))
- continue;
- was_call = true;
-
- new_insn = attempt;
- while (new_insn != NULL_RTX)
- {
- if (CALL_P (new_insn))
- break;
- new_insn = NEXT_INSN (new_insn);
- }
-
- gcc_assert (new_insn != NULL_RTX);
-
- CALL_INSN_FUNCTION_USAGE (new_insn)
- = CALL_INSN_FUNCTION_USAGE (old_insn);
-
- for (note = REG_NOTES (old_insn);
- note;
- note = XEXP (note, 1))
- switch (REG_NOTE_KIND (note))
- {
- case REG_NORETURN:
- case REG_SETJMP:
- add_reg_note (new_insn, REG_NOTE_KIND (note),
- XEXP (note, 0));
- break;
- default:
- /* Discard all other reg notes. */
- break;
- }
-
- /* Croak if there is another call in the sequence. */
- while (++i <= match_len)
- {
- j = i + peep2_current;
- if (j >= MAX_INSNS_PER_PEEP2 + 1)
- j -= MAX_INSNS_PER_PEEP2 + 1;
- old_insn = peep2_insn_data[j].insn;
- gcc_assert (!CALL_P (old_insn));
- }
- break;
- }
+ rtx attempt, head;
+ int match_len;
- i = match_len + peep2_current;
- if (i >= MAX_INSNS_PER_PEEP2 + 1)
- i -= MAX_INSNS_PER_PEEP2 + 1;
-
- note = find_reg_note (peep2_insn_data[i].insn,
- REG_EH_REGION, NULL_RTX);
-
- /* Replace the old sequence with the new. */
- attempt = emit_insn_after_setloc (attempt,
- peep2_insn_data[i].insn,
- INSN_LOCATOR (peep2_insn_data[i].insn));
- before_try = PREV_INSN (insn);
- delete_insn_chain (insn, peep2_insn_data[i].insn, false);
-
- /* Re-insert the EH_REGION notes. */
- if (note || (was_call && nonlocal_goto_handler_labels))
- {
- edge eh_edge;
- edge_iterator ei;
-
- FOR_EACH_EDGE (eh_edge, ei, bb->succs)
- if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL))
- break;
+ if (!past_end && !NONDEBUG_INSN_P (insn))
+ {
+ next_insn:
+ insn = NEXT_INSN (insn);
+ if (insn == NEXT_INSN (BB_END (bb)))
+ past_end = true;
+ continue;
+ }
+ if (!past_end && peep2_fill_buffer (bb, insn, live))
+ goto next_insn;
- if (note)
- copy_reg_eh_region_note_backward (note, attempt,
- before_try);
-
- if (eh_edge)
- for (x = attempt ; x != before_try ; x = PREV_INSN (x))
- if (x != BB_END (bb)
- && (can_throw_internal (x)
- || can_nonlocal_goto (x)))
- {
- edge nfte, nehe;
- int flags;
-
- nfte = split_block (bb, x);
- flags = (eh_edge->flags
- & (EDGE_EH | EDGE_ABNORMAL));
- if (CALL_P (x))
- flags |= EDGE_ABNORMAL_CALL;
- nehe = make_edge (nfte->src, eh_edge->dest,
- flags);
-
- nehe->probability = eh_edge->probability;
- nfte->probability
- = REG_BR_PROB_BASE - nehe->probability;
-
- do_cleanup_cfg |= purge_dead_edges (nfte->dest);
- bb = nfte->src;
- eh_edge = nehe;
- }
-
- /* Converting possibly trapping insn to non-trapping is
- possible. Zap dummy outgoing edges. */
- do_cleanup_cfg |= purge_dead_edges (bb);
- }
+ /* If we did not fill an empty buffer, it signals the end of the
+ block. */
+ if (peep2_current_count == 0)
+ break;
- if (targetm.have_conditional_execution ())
- {
- for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
- peep2_insn_data[i].insn = NULL_RTX;
- peep2_insn_data[peep2_current].insn = PEEP2_EOB;
- peep2_current_count = 0;
- }
- else
- {
- /* Back up lifetime information past the end of the
- newly created sequence. */
- if (++i >= MAX_INSNS_PER_PEEP2 + 1)
- i = 0;
- bitmap_copy (live, peep2_insn_data[i].live_before);
-
- /* Update life information for the new sequence. */
- x = attempt;
- do
- {
- if (INSN_P (x))
- {
- if (--i < 0)
- i = MAX_INSNS_PER_PEEP2;
- if (peep2_current_count < MAX_INSNS_PER_PEEP2
- && peep2_insn_data[i].insn == NULL_RTX)
- peep2_current_count++;
- peep2_insn_data[i].insn = x;
- df_insn_rescan (x);
- df_simulate_one_insn_backwards (bb, x, live);
- bitmap_copy (peep2_insn_data[i].live_before,
- live);
- }
- x = PREV_INSN (x);
- }
- while (x != prev);
+ /* The buffer filled to the current maximum, so try to match. */
- peep2_current = i;
- }
+ pos = peep2_buf_position (peep2_current + peep2_current_count);
+ peep2_insn_data[pos].insn = PEEP2_EOB;
+ COPY_REG_SET (peep2_insn_data[pos].live_before, live);
- /* If we generated a jump instruction, it won't have
- JUMP_LABEL set. Recompute after we're done. */
- for (x = attempt; x != before_try; x = PREV_INSN (x))
- if (JUMP_P (x))
- {
- do_rebuild_jump_labels = true;
- break;
- }
+ /* Match the peephole. */
+ head = peep2_insn_data[peep2_current].insn;
+ attempt = peephole2_insns (PATTERN (head), head, &match_len);
+ if (attempt != NULL)
+ {
+ rtx last = peep2_attempt (bb, head, match_len, attempt);
+ if (last)
+ {
+ peep2_update_life (bb, match_len, last, PREV_INSN (attempt));
+ continue;
}
}
- if (insn == BB_HEAD (bb))
- break;
+ /* No match: advance the buffer by one insn. */
+ peep2_current = peep2_buf_position (peep2_current + 1);
+ peep2_current_count--;
}
}
for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
BITMAP_FREE (peep2_insn_data[i].live_before);
BITMAP_FREE (live);
- if (do_rebuild_jump_labels)
+ if (peep2_do_rebuild_jump_labels)
rebuild_jump_labels (get_insns ());
}
#endif /* HAVE_peephole2 */