#include "debug.h"
#include "langhooks.h"
#include "tree-pass.h"
+#include "df.h"
/* Commonly used modes. */
return *slot;
}
+
+#if !HAVE_blockage
+/* Generate an empty ASM_INPUT, which is used to block attempts to schedule
+ across this insn. */
+
+rtx
+gen_blockage (void)
+{
+ rtx x = gen_rtx_ASM_INPUT (VOIDmode, "");
+ MEM_VOLATILE_P (x) = true;
+ return x;
+}
+#endif
+
+
/* Generate a new REG rtx. Make sure ORIGINAL_REGNO is set properly, and
don't attempt to share with the various global pieces of rtl (such as
frame_pointer_rtx). */
struct function *f = cfun;
rtx val;
- /* Don't let anything called after initial flow analysis create new
- registers. */
- gcc_assert (!no_new_pseudos);
+ gcc_assert (can_create_pseudo_p ());
if (generating_concat_p
&& (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
{
reset_used_flags (PATTERN (p));
reset_used_flags (REG_NOTES (p));
- reset_used_flags (LOG_LINKS (p));
}
/* Make sure that virtual stack slots are not shared. */
break;
case CONST:
- /* CONST can be shared if it contains a SYMBOL_REF. If it contains
- a LABEL_REF, it isn't sharable. */
- if (GET_CODE (XEXP (x, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
+ if (shared_const_p (orig))
return;
break;
{
reset_used_flags (PATTERN (p));
reset_used_flags (REG_NOTES (p));
- reset_used_flags (LOG_LINKS (p));
if (GET_CODE (PATTERN (p)) == SEQUENCE)
{
int i;
gcc_assert (INSN_P (q));
reset_used_flags (PATTERN (q));
reset_used_flags (REG_NOTES (q));
- reset_used_flags (LOG_LINKS (q));
}
}
}
{
verify_rtx_sharing (PATTERN (p), p);
verify_rtx_sharing (REG_NOTES (p), p);
- verify_rtx_sharing (LOG_LINKS (p), p);
}
}
{
PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
REG_NOTES (insn) = copy_rtx_if_shared (REG_NOTES (insn));
- LOG_LINKS (insn) = copy_rtx_if_shared (LOG_LINKS (insn));
}
}
break;
case CONST:
- /* CONST can be shared if it contains a SYMBOL_REF. If it contains
- a LABEL_REF, it isn't sharable. */
- if (GET_CODE (XEXP (x, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
+ if (shared_const_p (x))
return;
break;
insn_last = NEXT_INSN (insn_last);
}
+ /* We will be adding the new sequence to the function. The splitters
+ may have introduced invalid RTL sharing, so unshare the sequence now. */
+ unshare_all_rtl_in_chain (seq);
+
/* Mark labels. */
for (insn = insn_last; insn ; insn = PREV_INSN (insn))
{
INSN_UID (insn) = cur_insn_uid++;
PATTERN (insn) = pattern;
INSN_CODE (insn) = -1;
- LOG_LINKS (insn) = NULL;
REG_NOTES (insn) = NULL;
INSN_LOCATOR (insn) = curr_insn_locator ();
BLOCK_FOR_INSN (insn) = NULL;
PATTERN (insn) = pattern;
INSN_CODE (insn) = -1;
- LOG_LINKS (insn) = NULL;
REG_NOTES (insn) = NULL;
JUMP_LABEL (insn) = NULL;
INSN_LOCATOR (insn) = curr_insn_locator ();
PATTERN (insn) = pattern;
INSN_CODE (insn) = -1;
- LOG_LINKS (insn) = NULL;
REG_NOTES (insn) = NULL;
CALL_INSN_FUNCTION_USAGE (insn) = NULL;
INSN_LOCATOR (insn) = curr_insn_locator ();
SEQUENCE. */
void
-add_insn_after (rtx insn, rtx after)
+add_insn_after (rtx insn, rtx after, basic_block bb)
{
rtx next = NEXT_INSN (after);
- basic_block bb;
gcc_assert (!optimize || !INSN_DELETED_P (after));
{
set_block_for_insn (insn, bb);
if (INSN_P (insn))
- bb->flags |= BB_DIRTY;
+ df_insn_rescan (insn);
/* Should not happen as first in the BB is always
either NOTE or LABEL. */
if (BB_END (bb) == after
}
/* Add INSN into the doubly-linked list before insn BEFORE. This and
- the previous should be the only functions called to insert an insn once
- delay slots have been filled since only they know how to update a
- SEQUENCE. */
+ the previous should be the only functions called to insert an insn
+ once delay slots have been filled since only they know how to
+ update a SEQUENCE. If BB is NULL, an attempt is made to infer the
+ bb from before. */
void
-add_insn_before (rtx insn, rtx before)
+add_insn_before (rtx insn, rtx before, basic_block bb)
{
rtx prev = PREV_INSN (before);
- basic_block bb;
gcc_assert (!optimize || !INSN_DELETED_P (before));
gcc_assert (stack);
}
- if (!BARRIER_P (before)
- && !BARRIER_P (insn)
- && (bb = BLOCK_FOR_INSN (before)))
+ if (!bb
+ && !BARRIER_P (before)
+ && !BARRIER_P (insn))
+ bb = BLOCK_FOR_INSN (before);
+
+ if (bb)
{
set_block_for_insn (insn, bb);
if (INSN_P (insn))
- bb->flags |= BB_DIRTY;
+ df_insn_rescan (insn);
/* Should not happen as first in the BB is always either NOTE or
LABEL. */
gcc_assert (BB_HEAD (bb) != insn
PREV_INSN (XVECEXP (PATTERN (before), 0, 0)) = insn;
}
+
+/* Replace insn with an deleted instruction note. */
+
+void set_insn_deleted (rtx insn)
+{
+ df_insn_delete (BLOCK_FOR_INSN (insn), INSN_UID (insn));
+ PUT_CODE (insn, NOTE);
+ NOTE_KIND (insn) = NOTE_INSN_DELETED;
+}
+
+
/* Remove an insn from its doubly-linked list. This function knows how
to handle sequences. */
void
rtx prev = PREV_INSN (insn);
basic_block bb;
+ /* Later in the code, the block will be marked dirty. */
+ df_insn_delete (NULL, INSN_UID (insn));
+
if (prev)
{
NEXT_INSN (prev) = next;
&& (bb = BLOCK_FOR_INSN (insn)))
{
if (INSN_P (insn))
- bb->flags |= BB_DIRTY;
+ df_set_bb_dirty (bb);
if (BB_HEAD (bb) == insn)
{
/* Never ever delete the basic block note without deleting whole
&& (bb = BLOCK_FOR_INSN (after)))
{
rtx x;
- bb->flags |= BB_DIRTY;
+ df_set_bb_dirty (bb);
if (!BARRIER_P (from)
&& (bb2 = BLOCK_FOR_INSN (from)))
{
if (BB_END (bb2) == to)
BB_END (bb2) = prev;
- bb2->flags |= BB_DIRTY;
+ df_set_bb_dirty (bb2);
}
if (BB_END (bb) == after)
for (x = from; x != NEXT_INSN (to); x = NEXT_INSN (x))
if (!BARRIER_P (x))
- set_block_for_insn (x, bb);
+ {
+ set_block_for_insn (x, bb);
+ df_insn_change_bb (x);
+ }
}
}
/* Make X be output before the instruction BEFORE. */
rtx
-emit_insn_before_noloc (rtx x, rtx before)
+emit_insn_before_noloc (rtx x, rtx before, basic_block bb)
{
rtx last = before;
rtx insn;
while (insn)
{
rtx next = NEXT_INSN (insn);
- add_insn_before (insn, before);
+ add_insn_before (insn, before, bb);
last = insn;
insn = next;
}
default:
last = make_insn_raw (x);
- add_insn_before (last, before);
+ add_insn_before (last, before, bb);
break;
}
while (insn)
{
rtx next = NEXT_INSN (insn);
- add_insn_before (insn, before);
+ add_insn_before (insn, before, NULL);
last = insn;
insn = next;
}
default:
last = make_jump_insn_raw (x);
- add_insn_before (last, before);
+ add_insn_before (last, before, NULL);
break;
}
while (insn)
{
rtx next = NEXT_INSN (insn);
- add_insn_before (insn, before);
+ add_insn_before (insn, before, NULL);
last = insn;
insn = next;
}
default:
last = make_call_insn_raw (x);
- add_insn_before (last, before);
+ add_insn_before (last, before, NULL);
break;
}
INSN_UID (insn) = cur_insn_uid++;
- add_insn_before (insn, before);
+ add_insn_before (insn, before, NULL);
return insn;
}
if (INSN_UID (label) == 0)
{
INSN_UID (label) = cur_insn_uid++;
- add_insn_before (label, before);
+ add_insn_before (label, before, NULL);
}
return label;
BLOCK_FOR_INSN (note) = NULL;
memset (&NOTE_DATA (note), 0, sizeof (NOTE_DATA (note)));
- add_insn_before (note, before);
+ add_insn_before (note, before, NULL);
return note;
}
\f
/* Helper for emit_insn_after, handles lists of instructions
efficiently. */
-static rtx emit_insn_after_1 (rtx, rtx);
-
static rtx
-emit_insn_after_1 (rtx first, rtx after)
+emit_insn_after_1 (rtx first, rtx after, basic_block bb)
{
rtx last;
rtx after_after;
- basic_block bb;
+ if (!bb && !BARRIER_P (after))
+ bb = BLOCK_FOR_INSN (after);
- if (!BARRIER_P (after)
- && (bb = BLOCK_FOR_INSN (after)))
+ if (bb)
{
- bb->flags |= BB_DIRTY;
+ df_set_bb_dirty (bb);
for (last = first; NEXT_INSN (last); last = NEXT_INSN (last))
if (!BARRIER_P (last))
- set_block_for_insn (last, bb);
+ {
+ set_block_for_insn (last, bb);
+ df_insn_rescan (last);
+ }
if (!BARRIER_P (last))
- set_block_for_insn (last, bb);
+ {
+ set_block_for_insn (last, bb);
+ df_insn_rescan (last);
+ }
if (BB_END (bb) == after)
BB_END (bb) = last;
}
return last;
}
-/* Make X be output after the insn AFTER. */
+/* Make X be output after the insn AFTER and set the BB of insn. If
+ BB is NULL, an attempt is made to infer the BB from AFTER. */
rtx
-emit_insn_after_noloc (rtx x, rtx after)
+emit_insn_after_noloc (rtx x, rtx after, basic_block bb)
{
rtx last = after;
case CODE_LABEL:
case BARRIER:
case NOTE:
- last = emit_insn_after_1 (x, after);
+ last = emit_insn_after_1 (x, after, bb);
break;
#ifdef ENABLE_RTL_CHECKING
default:
last = make_insn_raw (x);
- add_insn_after (last, after);
+ add_insn_after (last, after, bb);
break;
}
case CODE_LABEL:
case BARRIER:
case NOTE:
- last = emit_insn_after_1 (x, after);
+ last = emit_insn_after_1 (x, after, NULL);
break;
#ifdef ENABLE_RTL_CHECKING
default:
last = make_jump_insn_raw (x);
- add_insn_after (last, after);
+ add_insn_after (last, after, NULL);
break;
}
case CODE_LABEL:
case BARRIER:
case NOTE:
- last = emit_insn_after_1 (x, after);
+ last = emit_insn_after_1 (x, after, NULL);
break;
#ifdef ENABLE_RTL_CHECKING
default:
last = make_call_insn_raw (x);
- add_insn_after (last, after);
+ add_insn_after (last, after, NULL);
break;
}
INSN_UID (insn) = cur_insn_uid++;
- add_insn_after (insn, after);
+ add_insn_after (insn, after, NULL);
return insn;
}
if (INSN_UID (label) == 0)
{
INSN_UID (label) = cur_insn_uid++;
- add_insn_after (label, after);
+ add_insn_after (label, after, NULL);
}
return label;
NOTE_KIND (note) = subtype;
BLOCK_FOR_INSN (note) = NULL;
memset (&NOTE_DATA (note), 0, sizeof (NOTE_DATA (note)));
- add_insn_after (note, after);
+ add_insn_after (note, after, NULL);
return note;
}
\f
rtx
emit_insn_after_setloc (rtx pattern, rtx after, int loc)
{
- rtx last = emit_insn_after_noloc (pattern, after);
+ rtx last = emit_insn_after_noloc (pattern, after, NULL);
if (pattern == NULL_RTX || !loc)
return last;
if (INSN_P (after))
return emit_insn_after_setloc (pattern, after, INSN_LOCATOR (after));
else
- return emit_insn_after_noloc (pattern, after);
+ return emit_insn_after_noloc (pattern, after, NULL);
}
/* Like emit_jump_insn_after_noloc, but set INSN_LOCATOR according to SCOPE. */
emit_insn_before_setloc (rtx pattern, rtx before, int loc)
{
rtx first = PREV_INSN (before);
- rtx last = emit_insn_before_noloc (pattern, before);
+ rtx last = emit_insn_before_noloc (pattern, before, NULL);
if (pattern == NULL_RTX || !loc)
return last;
if (INSN_P (before))
return emit_insn_before_setloc (pattern, before, INSN_LOCATOR (before));
else
- return emit_insn_before_noloc (pattern, before);
+ return emit_insn_before_noloc (pattern, before, NULL);
}
/* like emit_insn_before_noloc, but set insn_locator according to scope. */
set_unique_reg_note (rtx insn, enum reg_note kind, rtx datum)
{
rtx note = find_reg_note (insn, kind, NULL_RTX);
+ rtx new_note = NULL;
switch (kind)
{
It serves no useful purpose and breaks eliminate_regs. */
if (GET_CODE (datum) == ASM_OPERANDS)
return NULL_RTX;
+
+ if (note)
+ {
+ XEXP (note, 0) = datum;
+ df_notes_rescan (insn);
+ return note;
+ }
break;
default:
+ if (note)
+ {
+ XEXP (note, 0) = datum;
+ return note;
+ }
break;
}
- if (note)
+ new_note = gen_rtx_EXPR_LIST (kind, datum, REG_NOTES (insn));
+ REG_NOTES (insn) = new_note;
+
+ switch (kind)
{
- XEXP (note, 0) = datum;
- return note;
+ case REG_EQUAL:
+ case REG_EQUIV:
+ df_notes_rescan (insn);
+ break;
+ default:
+ break;
}
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (kind, datum, REG_NOTES (insn));
return REG_NOTES (insn);
}
\f
last_insn = last;
}
+/* Like push_to_sequence, but take the last insn as an argument to avoid
+ looping through the list. */
+
+void
+push_to_sequence2 (rtx first, rtx last)
+{
+ start_sequence ();
+
+ first_insn = first;
+ last_insn = last;
+}
+
/* Set up the outer-level insn chain
as the current sequence, saving the previously current one. */
break;
case CONST:
- /* CONST can be shared if it contains a SYMBOL_REF. If it contains
- a LABEL_REF, it isn't sharable. */
- if (GET_CODE (XEXP (orig, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
- && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT)
+ if (shared_const_p (orig))
return orig;
break;
const_tiny_rtx[i][(int) mode] = GEN_INT (i);
}
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_INT);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ rtx inner = const_tiny_rtx[0][(int)GET_MODE_INNER (mode)];
+ const_tiny_rtx[0][(int) mode] = gen_rtx_CONCAT (mode, inner, inner);
+ }
+
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ rtx inner = const_tiny_rtx[0][(int)GET_MODE_INNER (mode)];
+ const_tiny_rtx[0][(int) mode] = gen_rtx_CONCAT (mode, inner, inner);
+ }
+
for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))