regmove.c (discover_flags_reg): New function.

* regmove.c (discover_flags_reg): New function.
        (flags_set_1, mark_flags_life_zones): New functions.
        (regmove_optimize): Call them.
        (fixup_match_1): Use insn modes rather than sets_cc0_p.

From-SVN: r25332
This commit is contained in:
Richard Henderson 1999-02-19 15:02:58 -08:00 committed by Richard Henderson
parent 419ff8e1c2
commit dc2cb19139
2 changed files with 183 additions and 7 deletions

View file

@ -1,3 +1,10 @@
Fri Feb 19 23:02:02 1999 Richard Henderson <rth@cygnus.com>
* regmove.c (discover_flags_reg): New function.
(flags_set_1, mark_flags_life_zones): New functions.
(regmove_optimize): Call them.
(fixup_match_1): Use insn modes rather than sets_cc0_p.
Fri Feb 19 22:47:01 1999 J"orn Rennecke <amylaar@cygnus.co.uk>
* rtlanal.c (insn_first_p): Fix return value for insn == reference.

View file

@ -53,6 +53,10 @@ struct match {
int early_clobber[MAX_RECOG_OPERANDS];
};
static rtx discover_flags_reg PROTO((void));
static void mark_flags_life_zones PROTO((rtx));
static void flags_set_1 PROTO((rtx, rtx));
static int try_auto_increment PROTO((rtx, rtx, rtx, rtx, HOST_WIDE_INT, int));
static int find_matches PROTO((rtx, struct match *));
static int fixup_match_1 PROTO((rtx, rtx, rtx, rtx, rtx, int, int, int, FILE *))
@ -150,7 +154,172 @@ try_auto_increment (insn, inc_insn, inc_insn_set, reg, increment, pre)
}
return 0;
}
/* Determine if the pattern generated by add_optab has a clobber,
such as might be issued for a flags hard register. To make the
code elsewhere simpler, we handle cc0 in this same framework.
Return the register if one was discovered. Return NULL_RTX if
if no flags were found. Return pc_rtx if we got confused. */
static rtx
discover_flags_reg ()
{
rtx tmp;
tmp = gen_rtx_REG (SImode, 10000);
tmp = gen_add3_insn (tmp, tmp, GEN_INT (2));
/* If we get something that isn't a simple set, or a
[(set ..) (clobber ..)], this whole function will go wrong. */
if (GET_CODE (tmp) == SET)
return NULL_RTX;
else if (GET_CODE (tmp) == PARALLEL)
{
int found;
if (XVECLEN (tmp, 0) != 2)
return pc_rtx;
tmp = XVECEXP (tmp, 0, 1);
if (GET_CODE (tmp) != CLOBBER)
return pc_rtx;
tmp = XEXP (tmp, 0);
/* Don't do anything foolish if the md wanted to clobber a
scratch or something. We only care about hard regs.
Moreover we don't like the notion of subregs of hard regs. */
if (GET_CODE (tmp) == SUBREG
&& GET_CODE (SUBREG_REG (tmp)) == REG
&& REGNO (SUBREG_REG (tmp)) < FIRST_PSEUDO_REGISTER)
return pc_rtx;
found = (GET_CODE (tmp) == REG && REGNO (tmp) < FIRST_PSEUDO_REGISTER);
#ifdef HAVE_cc0
/* If we're cc0, and we found a potential flags reg, bail. */
return (found ? pc_rtx : cc0_rtx);
#else
return (found ? tmp : NULL_RTX);
#endif
}
return pc_rtx;
}
/* It is a tedious task identifying when the flags register is live and
when it is safe to optimize. Since we process the instruction stream
multiple times, locate and record these live zones by marking the
mode of the instructions --
QImode is used on the instruction at which the flags becomes live.
HImode is used within the range (exclusive) that the flags are
live. Thus the user of the flags is not marked.
All other instructions are cleared to VOIDmode. */
/* Used to communicate with flags_set_1. */
static rtx flags_set_1_rtx;
static int flags_set_1_set;
static void
mark_flags_life_zones (flags)
rtx flags;
{
int flags_regno;
int flags_nregs;
int block;
/* Simple cases first: if no flags, clear all modes. If confusing,
mark the entire function as being in a flags shadow. */
if (flags == NULL_RTX || flags == pc_rtx)
{
enum machine_mode mode = (flags ? HImode : VOIDmode);
rtx insn;
for (insn = get_insns(); insn; insn = NEXT_INSN (insn))
PUT_MODE (insn, mode);
return;
}
#ifdef HAVE_cc0
flags_regno = -1;
flags_nregs = 1;
#else
flags_regno = REGNO (flags);
flags_nregs = HARD_REGNO_NREGS (flags_regno, GET_MODE (flags));
#endif
flags_set_1_rtx = flags;
/* Process each basic block. */
for (block = n_basic_blocks - 1; block >= 0; block--)
{
rtx insn, end;
int live;
insn = BLOCK_HEAD (block);
end = BLOCK_END (block);
/* Look out for the (unlikely) case of flags being live across
basic block boundaries. */
live = 0;
#ifndef HAVE_cc0
{
int i;
for (i = 0; i < flags_nregs; ++i)
live |= REGNO_REG_SET_P (basic_block_live_at_start[block],
flags_regno + i);
}
#endif
while (1)
{
/* Process liveness in reverse order of importance --
alive, death, birth. This lets more important info
overwrite the mode of lesser info. */
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
#ifdef HAVE_cc0
/* In the cc0 case, death is not marked in reg notes,
but is instead the mere use of cc0 when it is alive. */
if (live && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
live = 0;
#else
/* In the hard reg case, we watch death notes. */
if (live && find_regno_note (insn, REG_DEAD, flags_regno))
live = 0;
#endif
PUT_MODE (insn, (live ? HImode : VOIDmode));
/* In either case, birth is denoted simply by it's presence
as the destination of a set. */
flags_set_1_set = 0;
note_stores (PATTERN (insn), flags_set_1);
if (flags_set_1_set)
{
live = 1;
PUT_MODE (insn, QImode);
}
}
else
PUT_MODE (insn, (live ? HImode : VOIDmode));
if (insn == end)
break;
insn = NEXT_INSN (insn);
}
}
}
/* A subroutine of mark_flags_life_zones, called through note_stores. */
static void
flags_set_1 (x, pat)
rtx x, pat;
{
if (GET_CODE (pat) == SET
&& reg_overlap_mentioned_p (x, flags_set_1_rtx))
flags_set_1_set = 1;
}
static int *regno_src_regno;
/* Indicate how good a choice REG (which appears as a source) is to replace
@ -908,6 +1077,10 @@ regmove_optimize (f, nregs, regmove_dump_file)
int i;
rtx copy_src, copy_dst;
/* Find out where a potential flags register is live, and so that we
can supress some optimizations in those zones. */
mark_flags_life_zones (discover_flags_reg ());
regno_src_regno = (int *)alloca (sizeof *regno_src_regno * nregs);
for (i = nregs; --i >= 0; ) regno_src_regno[i] = -1;
@ -1617,13 +1790,9 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
&& GET_CODE (SET_DEST (single_set (p))) == REG
&& (REGNO (SET_DEST (single_set (p)))
< FIRST_PSEUDO_REGISTER))
#ifdef HAVE_cc0
/* We may not emit an insn directly
after P if the latter sets CC0. */
&& ! sets_cc0_p (PATTERN (p))
#endif
)
/* We may only emit an insn directly after P if we
are not in the shadow of a live flags register. */
&& GET_MODE (p) == VOIDmode)
{
search_end = q;
q = insn;