From: Richard Henderson Date: Fri, 19 Feb 1999 23:02:58 +0000 (-0800) Subject: regmove.c (discover_flags_reg): New function. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=dc2cb19139f944afba7993591ce2db3eaa54bb7e;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a1946ef7246..7cee31cd5de 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +Fri Feb 19 23:02:02 1999 Richard Henderson + + * 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 * rtlanal.c (insn_first_p): Fix return value for insn == reference. diff --git a/gcc/regmove.c b/gcc/regmove.c index 70071ac7162..04fcb5da5a4 100644 --- a/gcc/regmove.c +++ b/gcc/regmove.c @@ -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;