#include "insn-config.h"
#include "recog.h"
#include "output.h"
-#include "reload.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "flags.h"
#include "basic-block.h"
#include "toplev.h"
+static int perhaps_ends_bb_p PARAMS ((rtx));
static int optimize_reg_copy_1 PARAMS ((rtx, rtx, rtx));
static void optimize_reg_copy_2 PARAMS ((rtx, rtx, rtx));
static void optimize_reg_copy_3 PARAMS ((rtx, rtx, rtx));
alive, death, birth. This lets more important info
overwrite the mode of lesser info. */
- if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ if (INSN_P (insn))
{
#ifdef HAVE_cc0
/* In the cc0 case, death is not marked in reg notes,
when the registers get tied. */
return 2;
}
+\f
+/* Return 1 if INSN might end a basic block. */
+
+static int perhaps_ends_bb_p (insn)
+ rtx insn;
+{
+ switch (GET_CODE (insn))
+ {
+ case CODE_LABEL:
+ case JUMP_INSN:
+ /* These always end a basic block. */
+ return 1;
+ case CALL_INSN:
+ /* A CALL_INSN might be the last insn of a basic block, if it is inside
+ an EH region or if there are nonlocal gotos. Note that this test is
+ very conservative. */
+ return flag_exceptions || nonlocal_goto_handler_labels;
+
+ default:
+ /* All others never end a basic block. */
+ return 0;
+ }
+}
+\f
/* INSN is a copy from SRC to DEST, both registers, and SRC does not die
in INSN.
for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
{
- if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
- break;
-
/* ??? We can't scan past the end of a basic block without updating
- the register lifetime info (REG_DEAD/basic_block_live_at_start).
- A CALL_INSN might be the last insn of a basic block, if it is inside
- an EH region. There is no easy way to tell, so we just always break
- when we see a CALL_INSN if flag_exceptions is nonzero. */
- if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+ the register lifetime info (REG_DEAD/basic_block_live_at_start). */
+ if (perhaps_ends_bb_p (p))
break;
-
- if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ else if (! INSN_P (p))
continue;
if (reg_set_p (src, p) || reg_set_p (dest, p)
for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
{
- if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
- break;
-
/* ??? We can't scan past the end of a basic block without updating
- the register lifetime info (REG_DEAD/basic_block_live_at_start).
- A CALL_INSN might be the last insn of a basic block, if it is inside
- an EH region. There is no easy way to tell, so we just always break
- when we see a CALL_INSN if flag_exceptions is nonzero. */
- if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+ the register lifetime info (REG_DEAD/basic_block_live_at_start). */
+ if (perhaps_ends_bb_p (p))
break;
-
- if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ else if (! INSN_P (p))
continue;
set = single_set (p);
/* Set to stop at next insn. */
for (q = insn; q != NEXT_INSN (p); q = NEXT_INSN (q))
- if (GET_RTX_CLASS (GET_CODE (q)) == 'i')
+ if (INSN_P (q))
{
if (reg_mentioned_p (dest, PATTERN (q)))
PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
|| REG_N_SETS (src_no) != 1)
return;
for (p = PREV_INSN (insn); p && ! reg_set_p (src_reg, p); p = PREV_INSN (p))
- {
- if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
- return;
+ /* ??? We can't scan past the end of a basic block without updating
+ the register lifetime info (REG_DEAD/basic_block_live_at_start). */
+ if (perhaps_ends_bb_p (p))
+ break;
- /* ??? We can't scan past the end of a basic block without updating
- the register lifetime info (REG_DEAD/basic_block_live_at_start).
- A CALL_INSN might be the last insn of a basic block, if it is inside
- an EH region. There is no easy way to tell, so we just always break
- when we see a CALL_INSN if flag_exceptions is nonzero. */
- if (flag_exceptions && GET_CODE (p) == CALL_INSN)
- return;
-
- if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
- continue;
- }
if (! p)
return;
subreg = gen_rtx_SUBREG (old_mode, src_reg, 0);
while (p = NEXT_INSN (p), p != insn)
{
- if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ if (! INSN_P (p))
continue;
/* Make a tenative change. */
{
rtx s;
- if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ if (! INSN_P (p))
continue;
s = single_set (p);
if (s != 0
{
rtx pset;
- if (GET_CODE (p) == CODE_LABEL
- || GET_CODE (p) == JUMP_INSN)
- break;
-
/* ??? We can't scan past the end of a basic block without updating
- the register lifetime info (REG_DEAD/basic_block_live_at_start).
- A CALL_INSN might be the last insn of a basic block, if it is inside
- an EH region. There is no easy way to tell, so we just always break
- when we see a CALL_INSN if flag_exceptions is nonzero. */
- if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+ the register lifetime info (REG_DEAD/basic_block_live_at_start). */
+ if (perhaps_ends_bb_p (p))
break;
-
- if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ else if (! INSN_P (p))
continue;
if (find_regno_note (p, REG_DEAD, REGNO (dst)))
if (GET_CODE (p) == CODE_LABEL
|| GET_CODE (p) == JUMP_INSN)
break;
- if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ if (! INSN_P (p))
continue;
if (reg_overlap_mentioned_p (dst, PATTERN (p)))
{
if (GET_CODE (p) == CODE_LABEL
|| GET_CODE (p) == JUMP_INSN)
break;
- if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ if (! INSN_P (p))
continue;
if (reg_overlap_mentioned_p (dst, PATTERN (p)))
{
continue;
if (match.early_clobber[match_no]
- && count_occurrences (PATTERN (insn), src) > 1)
+ && count_occurrences (PATTERN (insn), src, 0) > 1)
continue;
/* Make sure match_operand is the destination. */
for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
{
- if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ if (INSN_P (insn))
{
int op_no, match_no;
int success = 0;
continue;
if (match.early_clobber[match_no]
- && count_occurrences (PATTERN (insn), src) > 1)
+ && count_occurrences (PATTERN (insn), src, 0) > 1)
continue;
/* Make sure match_no is the destination. */
{
rtx pset;
- if (GET_CODE (p) == CODE_LABEL
- || GET_CODE (p) == JUMP_INSN)
- break;
-
/* ??? We can't scan past the end of a basic block without
updating the register lifetime info
- (REG_DEAD/basic_block_live_at_start).
- A CALL_INSN might be the last insn of a basic block, if
- it is inside an EH region. There is no easy way to tell,
- so we just always break when we see a CALL_INSN if
- flag_exceptions is nonzero. */
- if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+ (REG_DEAD/basic_block_live_at_start). */
+ if (perhaps_ends_bb_p (p))
break;
-
- if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ else if (! INSN_P (p))
continue;
length++;
DST is operand number MATCH_NUMBER in INSN.
If BACKWARD is nonzero, we have been called in a backward pass.
Return nonzero for success. */
+
static int
fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
match_number, regmove_dump_file)
for (length = s_length = 0, p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
{
- if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
- break;
-
/* ??? We can't scan past the end of a basic block without updating
- the register lifetime info (REG_DEAD/basic_block_live_at_start).
- A CALL_INSN might be the last insn of a basic block, if it is
- inside an EH region. There is no easy way to tell, so we just
- always break when we see a CALL_INSN if flag_exceptions is nonzero. */
- if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+ the register lifetime info (REG_DEAD/basic_block_live_at_start). */
+ if (perhaps_ends_bb_p (p))
break;
-
- if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ else if (! INSN_P (p))
continue;
length++;
break;
for (q = p; q; q = NEXT_INSN (q))
{
- if (GET_CODE (q) == CODE_LABEL || GET_CODE (q) == JUMP_INSN)
- {
- q = 0;
- break;
- }
-
/* ??? We can't scan past the end of a basic block without
updating the register lifetime info
- (REG_DEAD/basic_block_live_at_start).
- A CALL_INSN might be the last insn of a basic block, if
- it is inside an EH region. There is no easy way to tell,
- so we just always break when we see a CALL_INSN if
- flag_exceptions is nonzero. */
- if (flag_exceptions && GET_CODE (q) == CALL_INSN)
+ (REG_DEAD/basic_block_live_at_start). */
+ if (perhaps_ends_bb_p (q))
{
q = 0;
break;
}
-
- if (GET_RTX_CLASS (GET_CODE (q)) != 'i')
+ else if (! INSN_P (q))
continue;
- if (reg_overlap_mentioned_p (src, PATTERN (q))
- || reg_set_p (src, q))
+ else if (reg_overlap_mentioned_p (src, PATTERN (q))
+ || reg_set_p (src, q))
break;
}
if (q)
/* Reject out of range shifts. */
if (code != PLUS
&& (newconst < 0
- || (newconst
- >= GET_MODE_BITSIZE (GET_MODE (SET_SRC (set2))))))
+ || ((unsigned HOST_WIDE_INT) newconst
+ >= (GET_MODE_BITSIZE (GET_MODE
+ (SET_SRC (set2)))))))
break;
if (code == PLUS)
{
/* emit_insn_after_with_line_notes has no
return value, so search for the new insn. */
insn = p;
- while (GET_RTX_CLASS (GET_CODE (insn)) != 'i'
- || PATTERN (insn) != pat)
+ while (! INSN_P (insn) || PATTERN (insn) != pat)
insn = PREV_INSN (insn);
REG_NOTES (insn) = notes;
{
for (q = PREV_INSN (insn); q; q = PREV_INSN(q))
{
- if (GET_CODE (q) == CODE_LABEL || GET_CODE (q) == JUMP_INSN)
- {
- q = 0;
- break;
- }
-
/* ??? We can't scan past the end of a basic block without
updating the register lifetime info
- (REG_DEAD/basic_block_live_at_start).
- A CALL_INSN might be the last insn of a basic block, if
- it is inside an EH region. There is no easy way to tell,
- so we just always break when we see a CALL_INSN if
- flag_exceptions is nonzero. */
- if (flag_exceptions && GET_CODE (q) == CALL_INSN)
+ (REG_DEAD/basic_block_live_at_start). */
+ if (perhaps_ends_bb_p (q))
{
q = 0;
break;
}
-
- if (GET_RTX_CLASS (GET_CODE (q)) != 'i')
+ else if (! INSN_P (q))
continue;
+
s_length2++;
if (reg_set_p (src, q))
{
inc_dest = post_inc_set ? SET_DEST (post_inc_set) : src;
for (q = post_inc; (q = NEXT_INSN (q)); )
{
- if (GET_CODE (q) == CODE_LABEL || GET_CODE (q) == JUMP_INSN)
- break;
-
/* ??? We can't scan past the end of a basic block without updating
- the register lifetime info (REG_DEAD/basic_block_live_at_start).
- A CALL_INSN might be the last insn of a basic block, if it
- is inside an EH region. There is no easy way to tell so we
- just always break when we see a CALL_INSN if flag_exceptions
- is nonzero. */
- if (flag_exceptions && GET_CODE (q) == CALL_INSN)
+ the register lifetime info
+ (REG_DEAD/basic_block_live_at_start). */
+ if (perhaps_ends_bb_p (q))
break;
-
- if (GET_RTX_CLASS (GET_CODE (q)) != 'i')
+ else if (! INSN_P (q))
continue;
- if (src != inc_dest && (reg_overlap_mentioned_p (src, PATTERN (q))
- || reg_set_p (src, q)))
+ else if (src != inc_dest
+ && (reg_overlap_mentioned_p (src, PATTERN (q))
+ || reg_set_p (src, q)))
break;
- if (reg_set_p (inc_dest, q))
+ else if (reg_set_p (inc_dest, q))
break;
- if (reg_overlap_mentioned_p (inc_dest, PATTERN (q)))
+ else if (reg_overlap_mentioned_p (inc_dest, PATTERN (q)))
{
try_auto_increment (q, post_inc,
post_inc_set, inc_dest, newconst, 1);
}
}
}
+
/* Move the death note for DST to INSN if it is used
there. */
if (reg_overlap_mentioned_p (dst, PATTERN (insn)))
struct csa_memlist
{
HOST_WIDE_INT sp_offset;
- rtx insn, mem;
+ rtx insn, *mem;
struct csa_memlist *next;
};
static rtx single_set_for_csa PARAMS ((rtx));
static void free_csa_memlist PARAMS ((struct csa_memlist *));
static struct csa_memlist *record_one_stack_memref
- PARAMS ((rtx, rtx, struct csa_memlist *));
+ PARAMS ((rtx, rtx *, struct csa_memlist *));
static int try_apply_stack_adjustment
PARAMS ((rtx, struct csa_memlist *, HOST_WIDE_INT, HOST_WIDE_INT));
static void combine_stack_adjustments_for_block PARAMS ((basic_block));
+static int record_stack_memrefs PARAMS ((rtx *, void *));
/* Main entry point for stack adjustment combination. */
/* Recognize a MEM of the form (sp) or (plus sp const). */
static int
-stack_memref_p (mem)
- rtx mem;
+stack_memref_p (x)
+ rtx x;
{
- return (GET_CODE (mem) == MEM
- && (XEXP (mem, 0) == stack_pointer_rtx
- || (GET_CODE (XEXP (mem, 0)) == PLUS
- && XEXP (XEXP (mem, 0), 0) == stack_pointer_rtx
- && GET_CODE (XEXP (XEXP (mem, 0), 0)) == CONST_INT)));
+ if (GET_CODE (x) != MEM)
+ return 0;
+ x = XEXP (x, 0);
+
+ if (x == stack_pointer_rtx)
+ return 1;
+ if (GET_CODE (x) == PLUS
+ && XEXP (x, 0) == stack_pointer_rtx
+ && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ return 1;
+
+ return 0;
}
/* Recognize either normal single_set or the hack in i386.md for
static struct csa_memlist *
record_one_stack_memref (insn, mem, next_memlist)
- rtx insn, mem;
+ rtx insn, *mem;
struct csa_memlist *next_memlist;
{
struct csa_memlist *ml;
ml = (struct csa_memlist *) xmalloc (sizeof (*ml));
- if (XEXP (mem, 0) == stack_pointer_rtx)
+ if (XEXP (*mem, 0) == stack_pointer_rtx)
ml->sp_offset = 0;
else
- ml->sp_offset = INTVAL (XEXP (XEXP (mem, 0), 1));
+ ml->sp_offset = INTVAL (XEXP (XEXP (*mem, 0), 1));
ml->insn = insn;
ml->mem = mem;
for (ml = memlist; ml ; ml = ml->next)
{
HOST_WIDE_INT c = ml->sp_offset - delta;
+ rtx new = gen_rtx_MEM (GET_MODE (*ml->mem),
+ plus_constant (stack_pointer_rtx, c));
/* Don't reference memory below the stack pointer. */
if (c < 0)
return 0;
}
- validate_change (ml->insn, &XEXP (ml->mem, 0),
- plus_constant (stack_pointer_rtx, c), 1);
+ MEM_COPY_ATTRIBUTES (new, *ml->mem);
+ validate_change (ml->insn, ml->mem, new, 1);
}
if (apply_change_group ())
return 0;
}
+/* Called via for_each_rtx and used to record all stack memory references in
+ the insn and discard all other stack pointer references. */
+struct record_stack_memrefs_data
+{
+ rtx insn;
+ struct csa_memlist *memlist;
+};
+
+static int
+record_stack_memrefs (xp, data)
+ rtx *xp;
+ void *data;
+{
+ rtx x = *xp;
+ struct record_stack_memrefs_data *d =
+ (struct record_stack_memrefs_data *) data;
+ if (!x)
+ return 0;
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ if (!reg_mentioned_p (stack_pointer_rtx, x))
+ return -1;
+ /* We are not able to handle correctly all possible memrefs containing
+ stack pointer, so this check is neccesary. */
+ if (stack_memref_p (x))
+ {
+ d->memlist = record_one_stack_memref (d->insn, xp, d->memlist);
+ return -1;
+ }
+ return 1;
+ case REG:
+ /* ??? We want be able to handle non-memory stack pointer references
+ later. For now just discard all insns refering to stack pointer
+ outside mem expressions. We would probably want to teach
+ validate_replace to simplify expressions first. */
+ if (x == stack_pointer_rtx)
+ return 1;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
/* Subroutine of combine_stack_adjustments, called for each basic block. */
static void
struct csa_memlist *memlist = NULL;
rtx pending_delete;
rtx insn, next;
+ struct record_stack_memrefs_data data;
for (insn = bb->head; ; insn = next)
{
pending_delete = NULL_RTX;
next = NEXT_INSN (insn);
- if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ if (! INSN_P (insn))
goto processed;
set = single_set_for_csa (insn);
goto processed;
}
- /* Find loads from stack memory and record them. */
- if (last_sp_set && stack_memref_p (src))
- {
- memlist = record_one_stack_memref (insn, src, memlist);
- goto processed;
- }
-
- /* Find stores to stack memory and record them. */
- if (last_sp_set && stack_memref_p (dest))
- {
- memlist = record_one_stack_memref (insn, dest, memlist);
- goto processed;
- }
-
/* Find a predecrement of exactly the previous adjustment and
turn it into a direct store. Obviously we can't do this if
there were any intervening uses of the stack pointer. */
if (memlist == NULL
- && last_sp_adjust == GET_MODE_SIZE (GET_MODE (dest))
+ && (last_sp_adjust
+ == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest)))
&& GET_CODE (dest) == MEM
&& GET_CODE (XEXP (dest, 0)) == PRE_DEC
&& XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
+ && ! reg_mentioned_p (stack_pointer_rtx, src)
+ && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
&& validate_change (insn, &SET_DEST (set),
change_address (dest, VOIDmode,
stack_pointer_rtx), 0))
}
}
+ data.insn = insn;
+ data.memlist = memlist;
+ if (GET_CODE (insn) != CALL_INSN && last_sp_set
+ && !for_each_rtx (&PATTERN (insn), record_stack_memrefs, &data))
+ {
+ memlist = data.memlist;
+ goto processed;
+ }
+ memlist = data.memlist;
+
/* Otherwise, we were not able to process the instruction.
Do not continue collecting data across such a one. */
if (last_sp_set