diff options
Diffstat (limited to 'gcc/combine.c')
-rw-r--r-- | gcc/combine.c | 830 |
1 files changed, 458 insertions, 372 deletions
diff --git a/gcc/combine.c b/gcc/combine.c index 46cd6db62ad..2f806abc8cf 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -31,7 +31,7 @@ along with GCC; see the file COPYING3. If not see We also try to combine triplets of insns A, B and C when C has a link back to B and B has a link back to A. Likewise for a small number of quadruplets of insns A, B, C and D for which - there's high likelihood of of success. + there's high likelihood of success. LOG_LINKS does not have links for use of the CC0. They don't need to, because the insn that sets the CC0 is always immediately @@ -78,36 +78,20 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #include "system.h" #include "coretypes.h" -#include "tm.h" +#include "backend.h" +#include "predict.h" +#include "tree.h" #include "rtl.h" -#include "hash-set.h" -#include "machmode.h" -#include "vec.h" -#include "double-int.h" -#include "input.h" +#include "df.h" #include "alias.h" -#include "symtab.h" -#include "wide-int.h" -#include "inchash.h" -#include "tree.h" #include "stor-layout.h" #include "tm_p.h" #include "flags.h" #include "regs.h" -#include "hard-reg-set.h" -#include "predict.h" -#include "function.h" -#include "dominance.h" -#include "cfg.h" #include "cfgrtl.h" #include "cfgcleanup.h" -#include "basic-block.h" #include "insn-config.h" /* Include expr.h after insn-config.h so we get HAVE_conditional_move. */ -#include "hashtab.h" -#include "statistics.h" -#include "real.h" -#include "fixed-value.h" #include "expmed.h" #include "dojump.h" #include "explow.h" @@ -125,16 +109,14 @@ along with GCC; see the file COPYING3. If not see #include "rtlhooks-def.h" #include "params.h" #include "tree-pass.h" -#include "df.h" #include "valtrack.h" -#include "hash-map.h" -#include "is-a.h" -#include "plugin-api.h" -#include "ipa-ref.h" #include "cgraph.h" -#include "obstack.h" #include "rtl-iter.h" +#ifndef LOAD_EXTEND_OP +#define LOAD_EXTEND_OP(M) UNKNOWN +#endif + /* Number of attempts to combine instructions in this function. */ static int combine_attempts; @@ -554,12 +536,12 @@ target_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1, register. */ static rtx_insn * -combine_split_insns (rtx pattern, rtx insn) +combine_split_insns (rtx pattern, rtx_insn *insn) { rtx_insn *ret; unsigned int nregs; - ret = safe_as_a <rtx_insn *> (split_insns (pattern, insn)); + ret = split_insns (pattern, insn); nregs = max_reg_num (); if (nregs > reg_stat.length ()) reg_stat.safe_grow_cleared (nregs); @@ -686,7 +668,6 @@ find_single_use (rtx dest, rtx_insn *insn, rtx_insn **ploc) rtx *result; struct insn_link *link; -#ifdef HAVE_cc0 if (dest == cc0_rtx) { next = NEXT_INSN (insn); @@ -699,7 +680,6 @@ find_single_use (rtx dest, rtx_insn *insn, rtx_insn **ploc) *ploc = next; return result; } -#endif if (!REG_P (dest)) return 0; @@ -838,7 +818,6 @@ do_SUBST_MODE (rtx *into, machine_mode newval) #define SUBST_MODE(INTO, NEWVAL) do_SUBST_MODE (&(INTO), (NEWVAL)) -#ifndef HAVE_cc0 /* Similar to SUBST, but NEWVAL is a LOG_LINKS expression. */ static void @@ -864,7 +843,6 @@ do_SUBST_LINK (struct insn_link **into, struct insn_link *newval) } #define SUBST_LINK(oldval, newval) do_SUBST_LINK (&oldval, newval) -#endif /* Subroutine of try_combine. Determine whether the replacement patterns NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to insn_rtx_cost @@ -1026,14 +1004,11 @@ can_combine_def_p (df_ref def) /* Do not combine frame pointer adjustments. */ if ((regno == FRAME_POINTER_REGNUM && (!reload_completed || frame_pointer_needed)) -#if !HARD_FRAME_POINTER_IS_FRAME_POINTER - || (regno == HARD_FRAME_POINTER_REGNUM + || (!HARD_FRAME_POINTER_IS_FRAME_POINTER + && regno == HARD_FRAME_POINTER_REGNUM && (!reload_completed || frame_pointer_needed)) -#endif -#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM - || (regno == ARG_POINTER_REGNUM && fixed_regs[regno]) -#endif - ) + || (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + && regno == ARG_POINTER_REGNUM && fixed_regs[regno])) return false; return true; @@ -1143,10 +1118,8 @@ insn_a_feeds_b (rtx_insn *a, rtx_insn *b) FOR_EACH_LOG_LINK (links, b) if (links->insn == a) return true; -#ifdef HAVE_cc0 - if (sets_cc0_p (a)) + if (HAVE_cc0 && sets_cc0_p (a)) return true; -#endif return false; } @@ -1159,9 +1132,7 @@ static int combine_instructions (rtx_insn *f, unsigned int nregs) { rtx_insn *insn, *next; -#ifdef HAVE_cc0 rtx_insn *prev; -#endif struct insn_link *links, *nextlinks; rtx_insn *first; basic_block last_bb; @@ -1226,9 +1197,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs) FOR_BB_INSNS (this_basic_block, insn) if (INSN_P (insn) && BLOCK_FOR_INSN (insn)) { -#ifdef AUTO_INC_DEC rtx links; -#endif subst_low_luid = DF_INSN_LUID (insn); subst_insn = insn; @@ -1237,12 +1206,11 @@ combine_instructions (rtx_insn *f, unsigned int nregs) insn); record_dead_and_set_regs (insn); -#ifdef AUTO_INC_DEC - for (links = REG_NOTES (insn); links; links = XEXP (links, 1)) - if (REG_NOTE_KIND (links) == REG_INC) - set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX, - insn); -#endif + if (AUTO_INC_DEC) + for (links = REG_NOTES (insn); links; links = XEXP (links, 1)) + if (REG_NOTE_KIND (links) == REG_INC) + set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX, + insn); /* Record the current insn_rtx_cost of this instruction. */ if (NONJUMP_INSN_P (insn)) @@ -1336,7 +1304,6 @@ combine_instructions (rtx_insn *f, unsigned int nregs) } } -#ifdef HAVE_cc0 /* Try to combine a jump insn that uses CC0 with a preceding insn that sets CC0, and maybe with its logical predecessor as well. @@ -1344,7 +1311,8 @@ combine_instructions (rtx_insn *f, unsigned int nregs) We need this special code because data flow connections via CC0 do not get entered in LOG_LINKS. */ - if (JUMP_P (insn) + if (HAVE_cc0 + && JUMP_P (insn) && (prev = prev_nonnote_insn (insn)) != 0 && NONJUMP_INSN_P (prev) && sets_cc0_p (PATTERN (prev))) @@ -1362,7 +1330,7 @@ combine_instructions (rtx_insn *f, unsigned int nregs) } /* Do the same for an insn that explicitly references CC0. */ - if (NONJUMP_INSN_P (insn) + if (HAVE_cc0 && NONJUMP_INSN_P (insn) && (prev = prev_nonnote_insn (insn)) != 0 && NONJUMP_INSN_P (prev) && sets_cc0_p (PATTERN (prev)) @@ -1384,18 +1352,20 @@ combine_instructions (rtx_insn *f, unsigned int nregs) /* Finally, see if any of the insns that this insn links to explicitly references CC0. If so, try this insn, that insn, and its predecessor if it sets CC0. */ - FOR_EACH_LOG_LINK (links, insn) - if (NONJUMP_INSN_P (links->insn) - && GET_CODE (PATTERN (links->insn)) == SET - && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (links->insn))) - && (prev = prev_nonnote_insn (links->insn)) != 0 - && NONJUMP_INSN_P (prev) - && sets_cc0_p (PATTERN (prev)) - && (next = try_combine (insn, links->insn, - prev, NULL, &new_direct_jump_p, - last_combined_insn)) != 0) - goto retry; -#endif + if (HAVE_cc0) + { + FOR_EACH_LOG_LINK (links, insn) + if (NONJUMP_INSN_P (links->insn) + && GET_CODE (PATTERN (links->insn)) == SET + && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (links->insn))) + && (prev = prev_nonnote_insn (links->insn)) != 0 + && NONJUMP_INSN_P (prev) + && sets_cc0_p (PATTERN (prev)) + && (next = try_combine (insn, links->insn, + prev, NULL, &new_direct_jump_p, + last_combined_insn)) != 0) + goto retry; + } /* Try combining an insn with two different insns whose results it uses. */ @@ -1650,6 +1620,72 @@ setup_incoming_promotions (rtx_insn *first) } } +/* If MODE has a precision lower than PREC and SRC is a non-negative constant + that would appear negative in MODE, sign-extend SRC for use in nonzero_bits + because some machines (maybe most) will actually do the sign-extension and + this is the conservative approach. + + ??? For 2.5, try to tighten up the MD files in this regard instead of this + kludge. */ + +static rtx +sign_extend_short_imm (rtx src, machine_mode mode, unsigned int prec) +{ + if (GET_MODE_PRECISION (mode) < prec + && CONST_INT_P (src) + && INTVAL (src) > 0 + && val_signbit_known_set_p (mode, INTVAL (src))) + src = GEN_INT (INTVAL (src) | ~GET_MODE_MASK (mode)); + + return src; +} + +/* Update RSP for pseudo-register X from INSN's REG_EQUAL note (if one exists) + and SET. */ + +static void +update_rsp_from_reg_equal (reg_stat_type *rsp, rtx_insn *insn, const_rtx set, + rtx x) +{ + rtx reg_equal_note = insn ? find_reg_equal_equiv_note (insn) : NULL_RTX; + unsigned HOST_WIDE_INT bits = 0; + rtx reg_equal = NULL, src = SET_SRC (set); + unsigned int num = 0; + + if (reg_equal_note) + reg_equal = XEXP (reg_equal_note, 0); + + if (SHORT_IMMEDIATES_SIGN_EXTEND) + { + src = sign_extend_short_imm (src, GET_MODE (x), BITS_PER_WORD); + if (reg_equal) + reg_equal = sign_extend_short_imm (reg_equal, GET_MODE (x), BITS_PER_WORD); + } + + /* Don't call nonzero_bits if it cannot change anything. */ + if (rsp->nonzero_bits != ~(unsigned HOST_WIDE_INT) 0) + { + bits = nonzero_bits (src, nonzero_bits_mode); + if (reg_equal && bits) + bits &= nonzero_bits (reg_equal, nonzero_bits_mode); + rsp->nonzero_bits |= bits; + } + + /* Don't call num_sign_bit_copies if it cannot change anything. */ + if (rsp->sign_bit_copies != 1) + { + num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x)); + if (reg_equal && num != GET_MODE_PRECISION (GET_MODE (x))) + { + unsigned int numeq = num_sign_bit_copies (reg_equal, GET_MODE (x)); + if (num == 0 || numeq > num) + num = numeq; + } + if (rsp->sign_bit_copies == 0 || num < rsp->sign_bit_copies) + rsp->sign_bit_copies = num; + } +} + /* Called via note_stores. If X is a pseudo that is narrower than HOST_BITS_PER_WIDE_INT and is being set, record what bits are known zero. @@ -1665,7 +1701,6 @@ static void set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data) { rtx_insn *insn = (rtx_insn *) data; - unsigned int num; if (REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER @@ -1725,34 +1760,7 @@ set_nonzero_bits_and_sign_copies (rtx x, const_rtx set, void *data) if (SET_DEST (set) == x || (paradoxical_subreg_p (SET_DEST (set)) && SUBREG_REG (SET_DEST (set)) == x)) - { - rtx src = SET_SRC (set); - -#ifdef SHORT_IMMEDIATES_SIGN_EXTEND - /* If X is narrower than a word and SRC is a non-negative - constant that would appear negative in the mode of X, - sign-extend it for use in reg_stat[].nonzero_bits because some - machines (maybe most) will actually do the sign-extension - and this is the conservative approach. - - ??? For 2.5, try to tighten up the MD files in this regard - instead of this kludge. */ - - if (GET_MODE_PRECISION (GET_MODE (x)) < BITS_PER_WORD - && CONST_INT_P (src) - && INTVAL (src) > 0 - && val_signbit_known_set_p (GET_MODE (x), INTVAL (src))) - src = GEN_INT (INTVAL (src) | ~GET_MODE_MASK (GET_MODE (x))); -#endif - - /* Don't call nonzero_bits if it cannot change anything. */ - if (rsp->nonzero_bits != ~(unsigned HOST_WIDE_INT) 0) - rsp->nonzero_bits |= nonzero_bits (src, nonzero_bits_mode); - num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x)); - if (rsp->sign_bit_copies == 0 - || rsp->sign_bit_copies > num) - rsp->sign_bit_copies = num; - } + update_rsp_from_reg_equal (rsp, insn, set, x); else { rsp->nonzero_bits = GET_MODE_MASK (GET_MODE (x)); @@ -1781,9 +1789,7 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED, const_rtx set = 0; rtx src, dest; rtx_insn *p; -#ifdef AUTO_INC_DEC rtx link; -#endif bool all_adjacent = true; int (*is_volatile_p) (const_rtx); @@ -1914,6 +1920,15 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED, set = expand_field_assignment (set); src = SET_SRC (set), dest = SET_DEST (set); + /* Do not eliminate user-specified register if it is in an + asm input because we may break the register asm usage defined + in GCC manual if allow to do so. + Be aware that this may cover more cases than we expect but this + should be harmless. */ + if (REG_P (dest) && REG_USERVAR_P (dest) && HARD_REGISTER_P (dest) + && extract_asm_operands (PATTERN (i3))) + return 0; + /* Don't eliminate a store in the stack pointer. */ if (dest == stack_pointer_rtx /* Don't combine with an insn that sets a register to itself if it has @@ -2053,24 +2068,22 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED, Also insist that I3 not be a jump; if it were one and the incremented register were spilled, we would lose. */ -#ifdef AUTO_INC_DEC - for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) - if (REG_NOTE_KIND (link) == REG_INC - && (JUMP_P (i3) - || reg_used_between_p (XEXP (link, 0), insn, i3) - || (pred != NULL_RTX - && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (pred))) - || (pred2 != NULL_RTX - && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (pred2))) - || (succ != NULL_RTX - && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (succ))) - || (succ2 != NULL_RTX - && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (succ2))) - || reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i3)))) - return 0; -#endif + if (AUTO_INC_DEC) + for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_INC + && (JUMP_P (i3) + || reg_used_between_p (XEXP (link, 0), insn, i3) + || (pred != NULL_RTX + && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (pred))) + || (pred2 != NULL_RTX + && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (pred2))) + || (succ != NULL_RTX + && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (succ))) + || (succ2 != NULL_RTX + && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (succ2))) + || reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i3)))) + return 0; -#ifdef HAVE_cc0 /* Don't combine an insn that follows a CC0-setting insn. An insn that uses CC0 must not be separated from the one that sets it. We do, however, allow I2 to follow a CC0-setting insn if that insn @@ -2080,11 +2093,13 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED, It would be more logical to test whether CC0 occurs inside I1 or I2, but that would be much slower, and this ought to be equivalent. */ - p = prev_nonnote_insn (insn); - if (p && p != pred && NONJUMP_INSN_P (p) && sets_cc0_p (PATTERN (p)) - && ! all_adjacent) - return 0; -#endif + if (HAVE_cc0) + { + p = prev_nonnote_insn (insn); + if (p && p != pred && NONJUMP_INSN_P (p) && sets_cc0_p (PATTERN (p)) + && ! all_adjacent) + return 0; + } /* If we get here, we have passed all the tests and the combination is to be allowed. */ @@ -2199,13 +2214,11 @@ combinable_i3pat (rtx_insn *i3, rtx *loc, rtx i2dest, rtx i1dest, rtx i0dest, && REG_P (subdest) && reg_referenced_p (subdest, PATTERN (i3)) && REGNO (subdest) != FRAME_POINTER_REGNUM -#if !HARD_FRAME_POINTER_IS_FRAME_POINTER - && REGNO (subdest) != HARD_FRAME_POINTER_REGNUM -#endif -#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM - && (REGNO (subdest) != ARG_POINTER_REGNUM - || ! fixed_regs [REGNO (subdest)]) -#endif + && (HARD_FRAME_POINTER_IS_FRAME_POINTER + || REGNO (subdest) != HARD_FRAME_POINTER_REGNUM) + && (FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM + || (REGNO (subdest) != ARG_POINTER_REGNUM + || ! fixed_regs [REGNO (subdest)])) && REGNO (subdest) != STACK_POINTER_REGNUM) { if (*pi3dest_killed) @@ -2319,7 +2332,7 @@ likely_spilled_retval_1 (rtx x, const_rtx set, void *data) regno = REGNO (x); if (regno >= info->regno + info->nregs) return; - nregs = hard_regno_nregs[regno][GET_MODE (x)]; + nregs = REG_NREGS (x); if (regno + nregs <= info->regno) return; new_mask = (2U << (nregs - 1)) - 1; @@ -2354,7 +2367,7 @@ likely_spilled_retval_p (rtx_insn *insn) if (!REG_P (reg) || !targetm.calls.function_value_regno_p (REGNO (reg))) return 0; regno = REGNO (reg); - nregs = hard_regno_nregs[regno][GET_MODE (reg)]; + nregs = REG_NREGS (reg); if (nregs == 1) return 0; mask = (2U << (nregs - 1)) - 1; @@ -2426,8 +2439,7 @@ can_change_dest_mode (rtx x, int added_sets, machine_mode mode) registers than the old mode. */ if (regno < FIRST_PSEUDO_REGISTER) return (HARD_REGNO_MODE_OK (regno, mode) - && (hard_regno_nregs[regno][GET_MODE (x)] - >= hard_regno_nregs[regno][mode])); + && REG_NREGS (x) >= hard_regno_nregs[regno][mode]); /* Or a pseudo that is only used once. */ return (regno < reg_n_sets_max @@ -2516,7 +2528,6 @@ is_parallel_of_n_reg_sets (rtx pat, int n) return true; } -#ifndef HAVE_cc0 /* Return whether INSN, a PARALLEL of N register SETs (and maybe some CLOBBERs), can be split into individual SETs in that order, without changing semantics. */ @@ -2543,7 +2554,6 @@ can_split_parallel_of_n_reg_sets (rtx_insn *insn, int n) return true; } -#endif /* Try to combine the insns I0, I1 and I2 into I3. Here I0, I1 and I2 appear earlier than I3. @@ -2890,7 +2900,6 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, } } -#ifndef HAVE_cc0 /* If we have no I1 and I2 looks like: (parallel [(set (reg:CC X) (compare:CC OP (const_int 0))) (set Y OP)]) @@ -2904,7 +2913,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, This undoes a previous combination and allows us to match a branch-and- decrement insn. */ - if (i1 == 0 + if (!HAVE_cc0 && i1 == 0 && is_parallel_of_n_reg_sets (PATTERN (i2), 2) && (GET_MODE_CLASS (GET_MODE (SET_DEST (XVECEXP (PATTERN (i2), 0, 0)))) == MODE_CC) @@ -2936,7 +2945,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, /* If I2 is a PARALLEL of two SETs of REGs (and perhaps some CLOBBERs), make those two SETs separate I1 and I2 insns, and make an I0 that is the original I1. */ - if (i0 == 0 + if (!HAVE_cc0 && i0 == 0 && is_parallel_of_n_reg_sets (PATTERN (i2), 2) && can_split_parallel_of_n_reg_sets (i2, 2) && !reg_used_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 0)), i2, i3) @@ -2957,7 +2966,6 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 1)); } -#endif /* Verify that I2 and I1 are valid for combining. */ if (! can_combine_p (i2, i3, i0, i1, NULL, NULL, &i2dest, &i2src) @@ -3026,20 +3034,19 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, || GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_DEC))) /* It's not the exception. */ #endif -#ifdef AUTO_INC_DEC - { - rtx link; - for (link = REG_NOTES (i3); link; link = XEXP (link, 1)) - if (REG_NOTE_KIND (link) == REG_INC - && (reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i2)) - || (i1 != 0 - && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i1))))) - { - undo_all (); - return 0; - } - } -#endif + if (AUTO_INC_DEC) + { + rtx link; + for (link = REG_NOTES (i3); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_INC + && (reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i2)) + || (i1 != 0 + && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i1))))) + { + undo_all (); + return 0; + } + } /* See if the SETs in I1 or I2 need to be kept around in the merged instruction: whenever the value set there is still needed past I3. @@ -3089,7 +3096,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, if (added_sets_2) { if (GET_CODE (PATTERN (i2)) == PARALLEL) - i2pat = gen_rtx_SET (VOIDmode, i2dest, copy_rtx (i2src)); + i2pat = gen_rtx_SET (i2dest, copy_rtx (i2src)); else i2pat = copy_rtx (PATTERN (i2)); } @@ -3097,7 +3104,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, if (added_sets_1) { if (GET_CODE (PATTERN (i1)) == PARALLEL) - i1pat = gen_rtx_SET (VOIDmode, i1dest, copy_rtx (i1src)); + i1pat = gen_rtx_SET (i1dest, copy_rtx (i1src)); else i1pat = copy_rtx (PATTERN (i1)); } @@ -3105,7 +3112,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, if (added_sets_0) { if (GET_CODE (PATTERN (i0)) == PARALLEL) - i0pat = gen_rtx_SET (VOIDmode, i0dest, copy_rtx (i0src)); + i0pat = gen_rtx_SET (i0dest, copy_rtx (i0src)); else i0pat = copy_rtx (PATTERN (i0)); } @@ -3118,7 +3125,6 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, subst_insn = i3; -#ifndef HAVE_cc0 /* Many machines that don't use CC0 have insns that can both perform an arithmetic operation and set the condition code. These operations will be represented as a PARALLEL with the first element of the vector @@ -3130,7 +3136,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, needed, and make the PARALLEL by just replacing I2DEST in I3SRC with I2SRC. Later we will make the PARALLEL that contains I2. */ - if (i1 == 0 && added_sets_2 && GET_CODE (PATTERN (i3)) == SET + if (!HAVE_cc0 && i1 == 0 && added_sets_2 && GET_CODE (PATTERN (i3)) == SET && GET_CODE (SET_SRC (PATTERN (i3))) == COMPARE && CONST_INT_P (XEXP (SET_SRC (PATTERN (i3)), 1)) && rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest)) @@ -3216,11 +3222,10 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, /* Create new version of i2pat if needed; the below PARALLEL creation needs this to work correctly. */ if (! rtx_equal_p (i2src, op0)) - i2pat = gen_rtx_SET (VOIDmode, i2dest, op0); + i2pat = gen_rtx_SET (i2dest, op0); i2_is_used = 1; } } -#endif if (i2_is_used == 0) { @@ -3648,9 +3653,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, are set between I2 and I3. */ if (insn_code_number < 0 && (split = find_split_point (&newpat, i3, false)) != 0 -#ifdef HAVE_cc0 - && REG_P (i2dest) -#endif + && (!HAVE_cc0 || REG_P (i2dest)) /* We need I2DEST in the proper mode. If it is a hard register or the only use of a pseudo, we can change its mode. Make sure we don't change a hard register to have a mode that @@ -3709,12 +3712,26 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, split_code = GET_CODE (*split); } + /* Similarly for (plus (mult FOO (const_int pow2))). */ + if (split_code == PLUS + && GET_CODE (XEXP (*split, 0)) == MULT + && CONST_INT_P (XEXP (XEXP (*split, 0), 1)) + && INTVAL (XEXP (XEXP (*split, 0), 1)) > 0 + && (i = exact_log2 (UINTVAL (XEXP (XEXP (*split, 0), 1)))) >= 0) + { + rtx nsplit = XEXP (*split, 0); + SUBST (XEXP (*split, 0), gen_rtx_ASHIFT (GET_MODE (nsplit), + XEXP (nsplit, 0), GEN_INT (i))); + /* Update split_code because we may not have a multiply + anymore. */ + split_code = GET_CODE (*split); + } + #ifdef INSN_SCHEDULING /* If *SPLIT is a paradoxical SUBREG, when we split it, it should be written as a ZERO_EXTEND. */ if (split_code == SUBREG && MEM_P (SUBREG_REG (*split))) { -#ifdef LOAD_EXTEND_OP /* Or as a SIGN_EXTEND if LOAD_EXTEND_OP says that that's what it really is. */ if (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (*split))) @@ -3722,7 +3739,6 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, SUBST (*split, gen_rtx_SIGN_EXTEND (split_mode, SUBREG_REG (*split))); else -#endif SUBST (*split, gen_rtx_ZERO_EXTEND (split_mode, SUBREG_REG (*split))); } @@ -3742,7 +3758,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, /* Split "X = Y op Y" as "Z = Y; X = Z op Z". */ if (rtx_equal_p (src_op0, src_op1)) { - newi2pat = gen_rtx_SET (VOIDmode, newdest, src_op0); + newi2pat = gen_rtx_SET (newdest, src_op0); SUBST (XEXP (setsrc, 0), newdest); SUBST (XEXP (setsrc, 1), newdest); subst_done = true; @@ -3766,8 +3782,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, if ((rtx_equal_p (p,r) && rtx_equal_p (q,s)) || (rtx_equal_p (p,s) && rtx_equal_p (q,r))) { - newi2pat = gen_rtx_SET (VOIDmode, newdest, - XEXP (src_op0, 0)); + newi2pat = gen_rtx_SET (newdest, XEXP (src_op0, 0)); SUBST (XEXP (setsrc, 0), newdest); SUBST (XEXP (setsrc, 1), newdest); subst_done = true; @@ -3777,7 +3792,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, else if (rtx_equal_p (p,q) && rtx_equal_p (r,s)) { rtx tmp = simplify_gen_binary (code, mode, p, r); - newi2pat = gen_rtx_SET (VOIDmode, newdest, tmp); + newi2pat = gen_rtx_SET (newdest, tmp); SUBST (XEXP (setsrc, 0), newdest); SUBST (XEXP (setsrc, 1), newdest); subst_done = true; @@ -3787,7 +3802,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, if (!subst_done) { - newi2pat = gen_rtx_SET (VOIDmode, newdest, *split); + newi2pat = gen_rtx_SET (newdest, *split); SUBST (*split, newdest); } @@ -3920,9 +3935,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, && !(GET_CODE (SET_DEST (set1)) == SUBREG && find_reg_note (i2, REG_DEAD, SUBREG_REG (SET_DEST (set1)))) -#ifdef HAVE_cc0 - && !reg_referenced_p (cc0_rtx, set0) -#endif + && (!HAVE_cc0 || !reg_referenced_p (cc0_rtx, set0)) /* If I3 is a jump, ensure that set0 is a jump so that we do not create invalid RTL. */ && (!JUMP_P (i3) || SET_DEST (set0) == pc_rtx) @@ -3937,9 +3950,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, && !(GET_CODE (SET_DEST (set0)) == SUBREG && find_reg_note (i2, REG_DEAD, SUBREG_REG (SET_DEST (set0)))) -#ifdef HAVE_cc0 - && !reg_referenced_p (cc0_rtx, set1) -#endif + && (!HAVE_cc0 || !reg_referenced_p (cc0_rtx, set1)) /* If I3 is a jump, ensure that set1 is a jump so that we do not create invalid RTL. */ && (!JUMP_P (i3) || SET_DEST (set1) == pc_rtx) @@ -4004,19 +4015,18 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, } } -#ifdef HAVE_cc0 /* If I2 is the CC0 setter and I3 is the CC0 user then check whether they are adjacent to each other or not. */ - { - rtx_insn *p = prev_nonnote_insn (i3); - if (p && p != i2 && NONJUMP_INSN_P (p) && newi2pat - && sets_cc0_p (newi2pat)) - { - undo_all (); - return 0; - } - } -#endif + if (HAVE_cc0) + { + rtx_insn *p = prev_nonnote_insn (i3); + if (p && p != i2 && NONJUMP_INSN_P (p) && newi2pat + && sets_cc0_p (newi2pat)) + { + undo_all (); + return 0; + } + } /* Only allow this combination if insn_rtx_costs reports that the replacement instructions are cheaper than the originals. */ @@ -4638,15 +4648,25 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, return newi2pat ? i2 : i3; } -/* Undo all the modifications recorded in undobuf. */ +/* Get a marker for undoing to the current state. */ + +static void * +get_undo_marker (void) +{ + return undobuf.undos; +} + +/* Undo the modifications up to the marker. */ static void -undo_all (void) +undo_to_marker (void *marker) { struct undo *undo, *next; - for (undo = undobuf.undos; undo; undo = next) + for (undo = undobuf.undos; undo != marker; undo = next) { + gcc_assert (undo); + next = undo->next; switch (undo->kind) { @@ -4670,7 +4690,15 @@ undo_all (void) undobuf.frees = undo; } - undobuf.undos = 0; + undobuf.undos = (struct undo *) marker; +} + +/* Undo all the modifications recorded in undobuf. */ + +static void +undo_all (void) +{ + undo_to_marker (0); } /* We've committed to accepting the changes we made. Move all @@ -4721,11 +4749,10 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src) return find_split_point (&SUBREG_REG (x), insn, false); case MEM: -#ifdef HAVE_lo_sum /* If we have (mem (const ..)) or (mem (symbol_ref ...)), split it using LO_SUM and HIGH. */ - if (GET_CODE (XEXP (x, 0)) == CONST - || GET_CODE (XEXP (x, 0)) == SYMBOL_REF) + if (HAVE_lo_sum && (GET_CODE (XEXP (x, 0)) == CONST + || GET_CODE (XEXP (x, 0)) == SYMBOL_REF)) { machine_mode address_mode = get_address_mode (x); @@ -4735,7 +4762,6 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src) XEXP (x, 0))); return &XEXP (XEXP (x, 0), 0); } -#endif /* If we have a PLUS whose second operand is a constant and the address is not valid, perhaps will can split it up using @@ -4748,8 +4774,7 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src) MEM_ADDR_SPACE (x))) { rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER]; - rtx_insn *seq = combine_split_insns (gen_rtx_SET (VOIDmode, reg, - XEXP (x, 0)), + rtx_insn *seq = combine_split_insns (gen_rtx_SET (reg, XEXP (x, 0)), subst_insn); /* This should have produced two insns, each of which sets our @@ -4818,7 +4843,6 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src) break; case SET: -#ifdef HAVE_cc0 /* If SET_DEST is CC0 and SET_SRC is not an operand, a COMPARE, or a ZERO_EXTRACT, the most likely reason why this doesn't match is that we need to put the operand into a register. So split at that @@ -4831,7 +4855,6 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src) && ! (GET_CODE (SET_SRC (x)) == SUBREG && OBJECT_P (SUBREG_REG (SET_SRC (x))))) return &SET_SRC (x); -#endif /* See if we can split SET_SRC as it stands. */ split = find_split_point (&SET_SRC (x), insn, true); @@ -5096,7 +5119,10 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src) /* Split at a multiply-accumulate instruction. However if this is the SET_SRC, we likely do not have such an instruction and it's worthless to try this split. */ - if (!set_src && GET_CODE (XEXP (x, 0)) == MULT) + if (!set_src + && (GET_CODE (XEXP (x, 0)) == MULT + || (GET_CODE (XEXP (x, 0)) == ASHIFT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))) return loc; default: @@ -5333,10 +5359,10 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy) && ! (code == SUBREG && MODES_TIEABLE_P (GET_MODE (x), GET_MODE (SUBREG_REG (to)))) -#ifdef HAVE_cc0 - && ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx) -#endif - ) + && (!HAVE_cc0 + || (! (code == SET + && i == 1 + && XEXP (x, 0) == cc0_rtx)))) return gen_rtx_CLOBBER (VOIDmode, const0_rtx); if (code == SUBREG @@ -5463,6 +5489,51 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest, SUBST (XEXP (x, 1), temp); } + /* Try to fold this expression in case we have constants that weren't + present before. */ + temp = 0; + switch (GET_RTX_CLASS (code)) + { + case RTX_UNARY: + if (op0_mode == VOIDmode) + op0_mode = GET_MODE (XEXP (x, 0)); + temp = simplify_unary_operation (code, mode, XEXP (x, 0), op0_mode); + break; + case RTX_COMPARE: + case RTX_COMM_COMPARE: + { + machine_mode cmp_mode = GET_MODE (XEXP (x, 0)); + if (cmp_mode == VOIDmode) + { + cmp_mode = GET_MODE (XEXP (x, 1)); + if (cmp_mode == VOIDmode) + cmp_mode = op0_mode; + } + temp = simplify_relational_operation (code, mode, cmp_mode, + XEXP (x, 0), XEXP (x, 1)); + } + break; + case RTX_COMM_ARITH: + case RTX_BIN_ARITH: + temp = simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1)); + break; + case RTX_BITFIELD_OPS: + case RTX_TERNARY: + temp = simplify_ternary_operation (code, mode, op0_mode, XEXP (x, 0), + XEXP (x, 1), XEXP (x, 2)); + break; + default: + break; + } + + if (temp) + { + x = temp; + code = GET_CODE (temp); + op0_mode = VOIDmode; + mode = GET_MODE (temp); + } + /* If this is a simple operation applied to an IF_THEN_ELSE, try applying it to the arms of the IF_THEN_ELSE. This often simplifies things. Check for cases where both arms are testing the same @@ -5562,51 +5633,6 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest, } } - /* Try to fold this expression in case we have constants that weren't - present before. */ - temp = 0; - switch (GET_RTX_CLASS (code)) - { - case RTX_UNARY: - if (op0_mode == VOIDmode) - op0_mode = GET_MODE (XEXP (x, 0)); - temp = simplify_unary_operation (code, mode, XEXP (x, 0), op0_mode); - break; - case RTX_COMPARE: - case RTX_COMM_COMPARE: - { - machine_mode cmp_mode = GET_MODE (XEXP (x, 0)); - if (cmp_mode == VOIDmode) - { - cmp_mode = GET_MODE (XEXP (x, 1)); - if (cmp_mode == VOIDmode) - cmp_mode = op0_mode; - } - temp = simplify_relational_operation (code, mode, cmp_mode, - XEXP (x, 0), XEXP (x, 1)); - } - break; - case RTX_COMM_ARITH: - case RTX_BIN_ARITH: - temp = simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1)); - break; - case RTX_BITFIELD_OPS: - case RTX_TERNARY: - temp = simplify_ternary_operation (code, mode, op0_mode, XEXP (x, 0), - XEXP (x, 1), XEXP (x, 2)); - break; - default: - break; - } - - if (temp) - { - x = temp; - code = GET_CODE (temp); - op0_mode = VOIDmode; - mode = GET_MODE (temp); - } - /* First see if we can apply the inverse distributive law. */ if (code == PLUS || code == MINUS || code == AND || code == IOR || code == XOR) @@ -5635,11 +5661,7 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest, /* Make sure we pass the constant operand if any as the second one if this is a commutative operation. */ if (CONSTANT_P (inner_op0) && COMMUTATIVE_ARITH_P (x)) - { - rtx tem = inner_op0; - inner_op0 = inner_op1; - inner_op1 = tem; - } + std::swap (inner_op0, inner_op1); inner = simplify_binary_operation (code == MINUS ? PLUS : code == DIV ? MULT : code, @@ -5794,16 +5816,14 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest, SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0)); break; -#ifdef HAVE_lo_sum case LO_SUM: /* Convert (lo_sum (high FOO) FOO) to FOO. This is necessary so we can add in an offset. find_split_point will split this address up again if it doesn't match. */ - if (GET_CODE (XEXP (x, 0)) == HIGH + if (HAVE_lo_sum && GET_CODE (XEXP (x, 0)) == HIGH && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1))) return XEXP (x, 1); break; -#endif case PLUS: /* (plus (xor (and <foo> (const_int pow2 - 1)) <c>) <-c>) @@ -6190,7 +6210,7 @@ simplify_if_then_else (rtx x) if (false_code == EQ) { swapped = 1, true_code = EQ, false_code = NE; - temp = true_rtx, true_rtx = false_rtx, false_rtx = temp; + std::swap (true_rtx, false_rtx); } /* If we are comparing against zero and the expression being tested has @@ -6255,7 +6275,7 @@ simplify_if_then_else (rtx x) SUBST (XEXP (x, 1), false_rtx); SUBST (XEXP (x, 2), true_rtx); - temp = true_rtx, true_rtx = false_rtx, false_rtx = temp; + std::swap (true_rtx, false_rtx); cond = XEXP (x, 0); /* It is possible that the conditional has been simplified out. */ @@ -6584,13 +6604,12 @@ simplify_set (rtx x) else compare_mode = SELECT_CC_MODE (new_code, op0, op1); -#ifndef HAVE_cc0 /* If the mode changed, we have to change SET_DEST, the mode in the compare, and the mode in the place SET_DEST is used. If SET_DEST is a hard register, just build new versions with the proper mode. If it is a pseudo, we lose unless it is only time we set the pseudo, in which case we can safely change its mode. */ - if (compare_mode != GET_MODE (dest)) + if (!HAVE_cc0 && compare_mode != GET_MODE (dest)) { if (can_change_dest_mode (dest, 0, compare_mode)) { @@ -6612,7 +6631,6 @@ simplify_set (rtx x) dest = new_dest; } } -#endif /* cc0 */ #endif /* SELECT_CC_MODE */ /* If the code changed, we have to build a new comparison in @@ -6657,20 +6675,16 @@ simplify_set (rtx x) if (other_changed) undobuf.other_insn = other_insn; - /* Otherwise, if we didn't previously have a COMPARE in the - correct mode, we need one. */ - if (GET_CODE (src) != COMPARE || GET_MODE (src) != compare_mode) - { - SUBST (SET_SRC (x), gen_rtx_COMPARE (compare_mode, op0, op1)); - src = SET_SRC (x); - } - else if (GET_MODE (op0) == compare_mode && op1 == const0_rtx) + /* Don't generate a compare of a CC with 0, just use that CC. */ + if (GET_MODE (op0) == compare_mode && op1 == const0_rtx) { SUBST (SET_SRC (x), op0); src = SET_SRC (x); } - /* Otherwise, update the COMPARE if needed. */ - else if (XEXP (src, 0) != op0 || XEXP (src, 1) != op1) + /* Otherwise, if we didn't previously have the same COMPARE we + want, create it from scratch. */ + else if (GET_CODE (src) != COMPARE || GET_MODE (src) != compare_mode + || XEXP (src, 0) != op0 || XEXP (src, 1) != op1) { SUBST (SET_SRC (x), gen_rtx_COMPARE (compare_mode, op0, op1)); src = SET_SRC (x); @@ -6702,10 +6716,9 @@ simplify_set (rtx x) / UNITS_PER_WORD) == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)) -#ifndef WORD_REGISTER_OPERATIONS - && (GET_MODE_SIZE (GET_MODE (src)) - < GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))) -#endif + && (WORD_REGISTER_OPERATIONS + || (GET_MODE_SIZE (GET_MODE (src)) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))) #ifdef CANNOT_CHANGE_MODE_CLASS && ! (REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER && REG_CANNOT_CHANGE_MODE_P (REGNO (dest), @@ -6724,7 +6737,6 @@ simplify_set (rtx x) src = SET_SRC (x), dest = SET_DEST (x); } -#ifdef HAVE_cc0 /* If we have (set (cc0) (subreg ...)), we try to remove the subreg in SRC. */ if (dest == cc0_rtx @@ -6744,9 +6756,7 @@ simplify_set (rtx x) src = SET_SRC (x); } } -#endif -#ifdef LOAD_EXTEND_OP /* If we have (set FOO (subreg:M (mem:N BAR) 0)) with M wider than N, this would require a paradoxical subreg. Replace the subreg with a zero_extend to avoid the reload that would otherwise be required. */ @@ -6764,7 +6774,6 @@ simplify_set (rtx x) src = SET_SRC (x); } -#endif /* If we don't have a conditional move, SET_SRC is an IF_THEN_ELSE, and we are comparing an item known to be 0 or -1 against 0, use a logical @@ -6778,9 +6787,8 @@ simplify_set (rtx x) && (GET_CODE (XEXP (src, 0)) == EQ || GET_CODE (XEXP (src, 0)) == NE) && XEXP (XEXP (src, 0), 1) == const0_rtx && GET_MODE (src) == GET_MODE (XEXP (XEXP (src, 0), 0)) -#ifdef HAVE_conditional_move - && ! can_conditionally_move_p (GET_MODE (src)) -#endif + && (!HAVE_conditional_move + || ! can_conditionally_move_p (GET_MODE (src))) && (num_sign_bit_copies (XEXP (XEXP (src, 0), 0), GET_MODE (XEXP (XEXP (src, 0), 0))) == GET_MODE_PRECISION (GET_MODE (XEXP (XEXP (src, 0), 0)))) @@ -7015,15 +7023,16 @@ expand_compound_operation (rtx x) >> 1)) == 0))) { - rtx temp = gen_rtx_ZERO_EXTEND (GET_MODE (x), XEXP (x, 0)); + machine_mode mode = GET_MODE (x); + rtx temp = gen_rtx_ZERO_EXTEND (mode, XEXP (x, 0)); rtx temp2 = expand_compound_operation (temp); /* Make sure this is a profitable operation. */ - if (set_src_cost (x, optimize_this_for_speed_p) - > set_src_cost (temp2, optimize_this_for_speed_p)) + if (set_src_cost (x, mode, optimize_this_for_speed_p) + > set_src_cost (temp2, mode, optimize_this_for_speed_p)) return temp2; - else if (set_src_cost (x, optimize_this_for_speed_p) - > set_src_cost (temp, optimize_this_for_speed_p)) + else if (set_src_cost (x, mode, optimize_this_for_speed_p) + > set_src_cost (temp, mode, optimize_this_for_speed_p)) return temp; else return x; @@ -7191,7 +7200,7 @@ expand_field_assignment (const_rtx x) == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x)))) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))) { - x = gen_rtx_SET (VOIDmode, SUBREG_REG (SET_DEST (x)), + x = gen_rtx_SET (SUBREG_REG (SET_DEST (x)), gen_lowpart (GET_MODE (SUBREG_REG (SET_DEST (x))), SET_SRC (x))); @@ -7246,7 +7255,7 @@ expand_field_assignment (const_rtx x) mask), pos); - x = gen_rtx_SET (VOIDmode, copy_rtx (inner), + x = gen_rtx_SET (copy_rtx (inner), simplify_gen_binary (IOR, compute_mode, cleared, masked)); } @@ -7449,8 +7458,8 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos, /* Prefer ZERO_EXTENSION, since it gives more information to backends. */ - if (set_src_cost (temp, optimize_this_for_speed_p) - <= set_src_cost (temp1, optimize_this_for_speed_p)) + if (set_src_cost (temp, mode, optimize_this_for_speed_p) + <= set_src_cost (temp1, mode, optimize_this_for_speed_p)) return temp; return temp1; } @@ -7635,8 +7644,8 @@ make_extraction (machine_mode mode, rtx inner, HOST_WIDE_INT pos, /* Prefer ZERO_EXTENSION, since it gives more information to backends. */ - if (set_src_cost (temp1, optimize_this_for_speed_p) - < set_src_cost (temp, optimize_this_for_speed_p)) + if (set_src_cost (temp1, pos_mode, optimize_this_for_speed_p) + < set_src_cost (temp, pos_mode, optimize_this_for_speed_p)) temp = temp1; } pos_rtx = temp; @@ -7723,9 +7732,8 @@ extract_left_shift (rtx x, int count) We try, as much as possible, to re-use rtl expressions to save memory. IN_CODE says what kind of expression we are processing. Normally, it is - SET. In a memory address (inside a MEM, PLUS or minus, the latter two - being kludges), it is MEM. When processing the arguments of a comparison - or a COMPARE against zero, it is COMPARE. */ + SET. In a memory address it is MEM. When processing the arguments of + a comparison or a COMPARE against zero, it is COMPARE. */ rtx make_compound_operation (rtx x, enum rtx_code in_code) @@ -7745,8 +7753,6 @@ make_compound_operation (rtx x, enum rtx_code in_code) but once inside, go back to our default of SET. */ next_code = (code == MEM ? MEM - : ((code == PLUS || code == MINUS) - && SCALAR_INT_MODE_P (mode)) ? MEM : ((code == COMPARE || COMPARISON_P (x)) && XEXP (x, 1) == const0_rtx) ? COMPARE : in_code == COMPARE ? SET : in_code); @@ -7864,6 +7870,15 @@ make_compound_operation (rtx x, enum rtx_code in_code) new_rtx = make_extraction (GET_MODE (SUBREG_REG (XEXP (x, 0))), new_rtx, 0, XEXP (SUBREG_REG (XEXP (x, 0)), 1), i, 1, 0, in_code == COMPARE); + + /* If that didn't give anything, see if the AND simplifies on + its own. */ + if (!new_rtx && i >= 0) + { + new_rtx = make_compound_operation (XEXP (x, 0), next_code); + new_rtx = make_extraction (mode, new_rtx, 0, NULL_RTX, i, 1, + 0, in_code == COMPARE); + } } /* Same as previous, but for (xor/ior (lshiftrt...) (lshiftrt...)). */ else if ((GET_CODE (XEXP (x, 0)) == XOR @@ -8411,8 +8426,8 @@ force_to_mode (rtx x, machine_mode mode, unsigned HOST_WIDE_INT mask, y = simplify_gen_binary (AND, GET_MODE (x), XEXP (x, 0), gen_int_mode (cval, GET_MODE (x))); - if (set_src_cost (y, optimize_this_for_speed_p) - < set_src_cost (x, optimize_this_for_speed_p)) + if (set_src_cost (y, GET_MODE (x), optimize_this_for_speed_p) + < set_src_cost (x, GET_MODE (x), optimize_this_for_speed_p)) x = y; } @@ -9031,7 +9046,6 @@ static rtx known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val) { enum rtx_code code = GET_CODE (x); - rtx temp; const char *fmt; int i, j; @@ -9071,7 +9085,10 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val) else if (COMPARISON_P (x) || COMMUTATIVE_ARITH_P (x)) { if (rtx_equal_p (XEXP (x, 0), val)) - cond = swap_condition (cond), temp = val, val = reg, reg = temp; + { + std::swap (val, reg); + cond = swap_condition (cond); + } if (rtx_equal_p (XEXP (x, 0), reg) && rtx_equal_p (XEXP (x, 1), val)) { @@ -9256,7 +9273,7 @@ make_field_assignment (rtx x) assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1), 1, 1, 1, 0); if (assign != 0) - return gen_rtx_SET (VOIDmode, assign, const0_rtx); + return gen_rtx_SET (assign, const0_rtx); return x; } @@ -9273,7 +9290,7 @@ make_field_assignment (rtx x) XEXP (SUBREG_REG (XEXP (src, 0)), 1), 1, 1, 1, 0); if (assign != 0) - return gen_rtx_SET (VOIDmode, assign, const0_rtx); + return gen_rtx_SET (assign, const0_rtx); return x; } @@ -9286,7 +9303,7 @@ make_field_assignment (rtx x) assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1), 1, 1, 1, 0); if (assign != 0) - return gen_rtx_SET (VOIDmode, assign, const1_rtx); + return gen_rtx_SET (assign, const1_rtx); return x; } @@ -9309,7 +9326,7 @@ make_field_assignment (rtx x) /* Complete overlap. We can remove the source AND. */ if ((and_mask & ze_mask) == ze_mask) - return gen_rtx_SET (VOIDmode, dest, XEXP (src, 0)); + return gen_rtx_SET (dest, XEXP (src, 0)); /* Partial overlap. We can reduce the source AND. */ if ((and_mask & ze_mask) != and_mask) @@ -9317,7 +9334,7 @@ make_field_assignment (rtx x) mode = GET_MODE (src); src = gen_rtx_AND (mode, XEXP (src, 0), gen_int_mode (and_mask & ze_mask, mode)); - return gen_rtx_SET (VOIDmode, dest, src); + return gen_rtx_SET (dest, src); } } @@ -9418,7 +9435,7 @@ make_field_assignment (rtx x) == ((unsigned HOST_WIDE_INT) 1 << INTVAL (XEXP (assign, 1))) - 1) src = XEXP (src, 0); - return gen_rtx_SET (VOIDmode, assign, src); + return gen_rtx_SET (assign, src); } /* See if X is of the form (+ (* a c) (* b c)) and convert to (* (+ a b) c) @@ -9603,8 +9620,8 @@ distribute_and_simplify_rtx (rtx x, int n) tmp = apply_distributive_law (simplify_gen_binary (inner_code, mode, new_op0, new_op1)); if (GET_CODE (tmp) != outer_code - && (set_src_cost (tmp, optimize_this_for_speed_p) - < set_src_cost (x, optimize_this_for_speed_p))) + && (set_src_cost (tmp, mode, optimize_this_for_speed_p) + < set_src_cost (x, mode, optimize_this_for_speed_p))) return tmp; return NULL_RTX; @@ -9796,22 +9813,10 @@ reg_nonzero_bits_for_combine (const_rtx x, machine_mode mode, if (tem) { -#ifdef SHORT_IMMEDIATES_SIGN_EXTEND - /* If X is narrower than MODE and TEM is a non-negative - constant that would appear negative in the mode of X, - sign-extend it for use in reg_nonzero_bits because some - machines (maybe most) will actually do the sign-extension - and this is the conservative approach. - - ??? For 2.5, try to tighten up the MD files in this regard - instead of this kludge. */ - - if (GET_MODE_PRECISION (GET_MODE (x)) < GET_MODE_PRECISION (mode) - && CONST_INT_P (tem) - && INTVAL (tem) > 0 - && val_signbit_known_set_p (GET_MODE (x), INTVAL (tem))) - tem = GEN_INT (INTVAL (tem) | ~GET_MODE_MASK (GET_MODE (x))); -#endif + if (SHORT_IMMEDIATES_SIGN_EXTEND) + tem = sign_extend_short_imm (tem, GET_MODE (x), + GET_MODE_PRECISION (mode)); + return tem; } else if (nonzero_sign_valid && rsp->nonzero_bits) @@ -10846,21 +10851,11 @@ simplify_shift_const (rtx x, enum rtx_code code, machine_mode result_mode, } -/* Like recog, but we receive the address of a pointer to a new pattern. - We try to match the rtx that the pointer points to. - If that fails, we may try to modify or replace the pattern, - storing the replacement into the same pointer object. - - Modifications include deletion or addition of CLOBBERs. - - PNOTES is a pointer to a location where any REG_UNUSED notes added for - the CLOBBERs are placed. - - The value is the final insn code from the pattern ultimately matched, - or -1. */ +/* A subroutine of recog_for_combine. See there for arguments and + return value. */ static int -recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes) +recog_for_combine_1 (rtx *pnewpat, rtx_insn *insn, rtx *pnotes) { rtx pat = *pnewpat; rtx pat_without_clobbers; @@ -11007,6 +11002,110 @@ recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes) return insn_code_number; } + +/* Change every ZERO_EXTRACT and ZERO_EXTEND of a SUBREG that can be + expressed as an AND and maybe an LSHIFTRT, to that formulation. + Return whether anything was so changed. */ + +static bool +change_zero_ext (rtx *src) +{ + bool changed = false; + + subrtx_ptr_iterator::array_type array; + FOR_EACH_SUBRTX_PTR (iter, array, src, NONCONST) + { + rtx x = **iter; + machine_mode mode = GET_MODE (x); + int size; + + if (GET_CODE (x) == ZERO_EXTRACT + && CONST_INT_P (XEXP (x, 1)) + && CONST_INT_P (XEXP (x, 2)) + && GET_MODE (XEXP (x, 0)) == mode) + { + size = INTVAL (XEXP (x, 1)); + + int start = INTVAL (XEXP (x, 2)); + if (BITS_BIG_ENDIAN) + start = GET_MODE_PRECISION (mode) - size - start; + + x = gen_rtx_LSHIFTRT (mode, XEXP (x, 0), GEN_INT (start)); + } + else if (GET_CODE (x) == ZERO_EXTEND + && GET_CODE (XEXP (x, 0)) == SUBREG + && GET_MODE (SUBREG_REG (XEXP (x, 0))) == mode + && subreg_lowpart_p (XEXP (x, 0))) + { + size = GET_MODE_PRECISION (GET_MODE (XEXP (x, 0))); + x = SUBREG_REG (XEXP (x, 0)); + } + else + continue; + + unsigned HOST_WIDE_INT mask = 1; + mask <<= size; + mask--; + + x = gen_rtx_AND (mode, x, GEN_INT (mask)); + + SUBST (**iter, x); + changed = true; + } + + return changed; +} + +/* Like recog, but we receive the address of a pointer to a new pattern. + We try to match the rtx that the pointer points to. + If that fails, we may try to modify or replace the pattern, + storing the replacement into the same pointer object. + + Modifications include deletion or addition of CLOBBERs. If the + instruction will still not match, we change ZERO_EXTEND and ZERO_EXTRACT + to the equivalent AND and perhaps LSHIFTRT patterns, and try with that + (and undo if that fails). + + PNOTES is a pointer to a location where any REG_UNUSED notes added for + the CLOBBERs are placed. + + The value is the final insn code from the pattern ultimately matched, + or -1. */ + +static int +recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes) +{ + rtx pat = PATTERN (insn); + int insn_code_number = recog_for_combine_1 (pnewpat, insn, pnotes); + if (insn_code_number >= 0 || check_asm_operands (pat)) + return insn_code_number; + + void *marker = get_undo_marker (); + bool changed = false; + + if (GET_CODE (pat) == SET) + changed = change_zero_ext (&SET_SRC (pat)); + else if (GET_CODE (pat) == PARALLEL) + { + int i; + for (i = 0; i < XVECLEN (pat, 0); i++) + { + rtx set = XVECEXP (pat, 0, i); + if (GET_CODE (set) == SET) + changed |= change_zero_ext (&SET_SRC (set)); + } + } + + if (changed) + { + insn_code_number = recog_for_combine_1 (pnewpat, insn, pnotes); + + if (insn_code_number < 0) + undo_to_marker (marker); + } + + return insn_code_number; +} /* Like gen_lowpart_general but for use by combine. In combine it is not possible to create any new pseudoregs. However, it is @@ -11324,7 +11423,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1) /* Try a few ways of applying the same transformation to both operands. */ while (1) { -#ifndef WORD_REGISTER_OPERATIONS +#if !WORD_REGISTER_OPERATIONS /* The test below this one won't handle SIGN_EXTENDs on these machines, so check specially. */ if (code != GTU && code != GEU && code != LTU && code != LEU @@ -11460,7 +11559,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1) is already a constant integer. */ if (swap_commutative_operands_p (op0, op1)) { - tem = op0, op0 = op1, op1 = tem; + std::swap (op0, op1); code = swap_condition (code); } @@ -11978,11 +12077,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1) However, if we commute the AND inside the SUBREG then they no longer have defined values and the meaning of the code has been changed. */ - && (0 -#ifdef WORD_REGISTER_OPERATIONS - || (mode_width > GET_MODE_PRECISION (tmode) - && mode_width <= BITS_PER_WORD) -#endif + && ((WORD_REGISTER_OPERATIONS + && mode_width > GET_MODE_PRECISION (tmode) + && mode_width <= BITS_PER_WORD) || (mode_width <= GET_MODE_PRECISION (tmode) && subreg_lowpart_p (XEXP (op0, 0)))) && CONST_INT_P (XEXP (op0, 1)) @@ -12347,7 +12444,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1) /* We may have changed the comparison operands. Re-canonicalize. */ if (swap_commutative_operands_p (op0, op1)) { - tem = op0, op0 = op1, op1 = tem; + std::swap (op0, op1); code = swap_condition (code); } @@ -13193,11 +13290,9 @@ mark_used_regs_combine (rtx x) case ADDR_VEC: case ADDR_DIFF_VEC: case ASM_INPUT: -#ifdef HAVE_cc0 /* CC0 must die in the insn after it is set, so we don't need to take special note of it here. */ case CC0: -#endif return; case CLOBBER: @@ -13215,12 +13310,10 @@ mark_used_regs_combine (rtx x) { /* None of this applies to the stack, frame or arg pointers. */ if (regno == STACK_POINTER_REGNUM -#if !HARD_FRAME_POINTER_IS_FRAME_POINTER - || regno == HARD_FRAME_POINTER_REGNUM -#endif -#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM - || (regno == ARG_POINTER_REGNUM && fixed_regs[regno]) -#endif + || (!HARD_FRAME_POINTER_IS_FRAME_POINTER + && regno == HARD_FRAME_POINTER_REGNUM) + || (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + && regno == ARG_POINTER_REGNUM && fixed_regs[regno]) || regno == FRAME_POINTER_REGNUM) return; @@ -13334,8 +13427,8 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_luid, rtx_insn *to_insn, > GET_MODE_SIZE (GET_MODE (x)))) { unsigned int deadregno = REGNO (XEXP (note, 0)); - unsigned int deadend = END_HARD_REGNO (XEXP (note, 0)); - unsigned int ourend = END_HARD_REGNO (x); + unsigned int deadend = END_REGNO (XEXP (note, 0)); + unsigned int ourend = END_REGNO (x); unsigned int i; for (i = deadregno; i < deadend; i++) @@ -13353,9 +13446,9 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_luid, rtx_insn *to_insn, && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0))) < GET_MODE_SIZE (GET_MODE (x))))) && regno < FIRST_PSEUDO_REGISTER - && hard_regno_nregs[regno][GET_MODE (x)] > 1) + && REG_NREGS (x) > 1) { - unsigned int ourend = END_HARD_REGNO (x); + unsigned int ourend = END_REGNO (x); unsigned int i, offset; rtx oldnotes = 0; @@ -13808,9 +13901,7 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2, { rtx set = single_set (tem_insn); rtx inner_dest = 0; -#ifdef HAVE_cc0 rtx_insn *cc0_setter = NULL; -#endif if (set != 0) for (inner_dest = SET_DEST (set); @@ -13830,12 +13921,10 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2, if (set != 0 && ! side_effects_p (SET_SRC (set)) && rtx_equal_p (XEXP (note, 0), inner_dest) -#ifdef HAVE_cc0 - && (! reg_mentioned_p (cc0_rtx, SET_SRC (set)) - || ((cc0_setter = prev_cc0_setter (tem_insn)) != NULL - && sets_cc0_p (PATTERN (cc0_setter)) > 0)) -#endif - ) + && (!HAVE_cc0 + || (! reg_mentioned_p (cc0_rtx, SET_SRC (set)) + || ((cc0_setter = prev_cc0_setter (tem_insn)) != NULL + && sets_cc0_p (PATTERN (cc0_setter)) > 0)))) { /* Move the notes and links of TEM_INSN elsewhere. This might delete other dead insns recursively. @@ -13854,7 +13943,6 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2, if (tem_insn == i2) i2 = NULL; -#ifdef HAVE_cc0 /* Delete the setter too. */ if (cc0_setter) { @@ -13871,7 +13959,6 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2, if (cc0_setter == i2) i2 = NULL; } -#endif } else { @@ -13952,10 +14039,9 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2, be dead; so we recourse, and the recursive call then finds the previous insn that used this register. */ - if (place && regno < FIRST_PSEUDO_REGISTER - && hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] > 1) + if (place && REG_NREGS (XEXP (note, 0)) > 1) { - unsigned int endregno = END_HARD_REGNO (XEXP (note, 0)); + unsigned int endregno = END_REGNO (XEXP (note, 0)); bool all_used = true; unsigned int i; |