X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcombine.c;h=31efa5b84b627bbd7bc374864a3a257de89706c8;hb=f56cac0d51ddbeb3f90457641138937e02e11d12;hp=2265eb3e53771567db0fd941ed0f89ef952d69d8;hpb=0b8c18c9cf034d0ddda90f0fe084af67b083e4bc;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/combine.c b/gcc/combine.c index 2265eb3e537..31efa5b84b6 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -445,7 +445,7 @@ static void update_table_tick PROTO((rtx)); static void record_value_for_reg PROTO((rtx, rtx, rtx)); static void record_dead_and_set_regs_1 PROTO((rtx, rtx)); static void record_dead_and_set_regs PROTO((rtx)); -static int get_last_value_validate PROTO((rtx *, int, int)); +static int get_last_value_validate PROTO((rtx *, rtx, int, int)); static rtx get_last_value PROTO((rtx)); static int use_crosses_set_p PROTO((rtx, int)); static void reg_dead_at_p_1 PROTO((rtx, rtx)); @@ -2699,6 +2699,14 @@ find_split_point (loc, insn) case SIGN_EXTEND: inner = XEXP (SET_SRC (x), 0); + + /* We can't optimize if either mode is a partial integer + mode as we don't know how many bits are significant + in those modes. */ + if (GET_MODE_CLASS (GET_MODE (inner)) == MODE_PARTIAL_INT + || GET_MODE_CLASS (GET_MODE (SET_SRC (x))) == MODE_PARTIAL_INT) + break; + pos = 0; len = GET_MODE_BITSIZE (GET_MODE (inner)); unsignedp = 0; @@ -3375,7 +3383,7 @@ simplify_rtx (x, op0_mode, last, in_dest) if (CONSTANT_P (SUBREG_REG (x)) && op0_mode != VOIDmode && GET_MODE_SIZE (mode) == UNITS_PER_WORD - && GET_MODE_SIZE (op0_mode) < UNITS_PER_WORD + && GET_MODE_SIZE (op0_mode) > UNITS_PER_WORD && GET_MODE_CLASS (mode) == MODE_INT) { temp = operand_subword (SUBREG_REG (x), SUBREG_WORD (x), @@ -3387,8 +3395,16 @@ simplify_rtx (x, op0_mode, last, in_dest) /* If we want a subreg of a constant, at offset 0, take the low bits. On a little-endian machine, that's always valid. On a big-endian machine, it's valid - only if the constant's mode fits in one word. */ - if (CONSTANT_P (SUBREG_REG (x)) && subreg_lowpart_p (x) + only if the constant's mode fits in one word. Note that we + cannot use subreg_lowpart_p since SUBREG_REG may be VOIDmode. */ + if (CONSTANT_P (SUBREG_REG (x)) + && ((GET_MODE_SIZE (op0_mode) <= UNITS_PER_WORD + || ! WORDS_BIG_ENDIAN) + ? SUBREG_WORD (x) == 0 + : (SUBREG_WORD (x) + == ((GET_MODE_SIZE (op0_mode) + - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)) + / UNITS_PER_WORD))) && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode) && (! WORDS_BIG_ENDIAN || GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD)) @@ -3582,6 +3598,12 @@ simplify_rtx (x, op0_mode, last, in_dest) break; case TRUNCATE: + /* We can't handle truncation to a partial integer mode here + because we don't know the real bitsize of the partial + integer mode. */ + if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT) + break; + if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) SUBST (XEXP (x, 0), force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)), @@ -6490,6 +6512,14 @@ if_then_else_cond (x, ptrue, pfalse) if ((cond0 != 0 || cond1 != 0) && ! (cond0 != 0 && cond1 != 0 && ! rtx_equal_p (cond0, cond1))) { + /* If if_then_else_cond returned zero, then true/false are the + same rtl. We must copy one of them to prevent invalid rtl + sharing. */ + if (cond0 == 0) + true0 = copy_rtx (true0); + else if (cond1 == 0) + true1 = copy_rtx (true1); + *ptrue = gen_binary (code, mode, true0, true1); *pfalse = gen_binary (code, mode, false0, false1); return cond0 ? cond0 : cond1; @@ -10173,11 +10203,12 @@ record_value_for_reg (reg, insn, value) /* The value being assigned might refer to X (like in "x++;"). In that case, we must replace it with (clobber (const_int 0)) to prevent infinite loops. */ - if (value && ! get_last_value_validate (&value, + if (value && ! get_last_value_validate (&value, insn, reg_last_set_label[regno], 0)) { value = copy_rtx (value); - if (! get_last_value_validate (&value, reg_last_set_label[regno], 1)) + if (! get_last_value_validate (&value, insn, + reg_last_set_label[regno], 1)) value = 0; } @@ -10298,8 +10329,9 @@ record_dead_and_set_regs (insn) we don't know exactly what registers it was produced from. */ static int -get_last_value_validate (loc, tick, replace) +get_last_value_validate (loc, insn, tick, replace) rtx *loc; + rtx insn; int tick; int replace; { @@ -10329,10 +10361,20 @@ get_last_value_validate (loc, tick, replace) return 1; } + /* If this is a memory reference, make sure that there were + no stores after it that might have clobbered the value. We don't + have alias info, so we assume any store invalidates it. */ + else if (GET_CODE (x) == MEM && ! RTX_UNCHANGING_P (x) + && INSN_CUID (insn) <= mem_last_set) + { + if (replace) + *loc = gen_rtx (CLOBBER, GET_MODE (x), const0_rtx); + return replace; + } for (i = 0; i < len; i++) if ((fmt[i] == 'e' - && get_last_value_validate (&XEXP (x, i), tick, replace) == 0) + && get_last_value_validate (&XEXP (x, i), insn, tick, replace) == 0) /* Don't bother with these. They shouldn't occur anyway. */ || fmt[i] == 'E') return 0; @@ -10429,14 +10471,16 @@ get_last_value (x) } /* If the value has all its registers valid, return it. */ - if (get_last_value_validate (&value, reg_last_set_label[regno], 0)) + if (get_last_value_validate (&value, reg_last_set[regno], + reg_last_set_label[regno], 0)) return value; /* Otherwise, make a copy and replace any invalid register with (clobber (const_int 0)). If that fails for some reason, return 0. */ value = copy_rtx (value); - if (get_last_value_validate (&value, reg_last_set_label[regno], 1)) + if (get_last_value_validate (&value, reg_last_set[regno], + reg_last_set_label[regno], 1)) return value; return 0; @@ -10770,7 +10814,7 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes) if (note != 0 && regno < FIRST_PSEUDO_REGISTER && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0))) - != GET_MODE_SIZE (GET_MODE (x)))) + > GET_MODE_SIZE (GET_MODE (x)))) { int deadregno = REGNO (XEXP (note, 0)); int deadend @@ -10786,18 +10830,28 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes) gen_rtx (REG, reg_raw_mode[i], i), REG_NOTES (where_dead)); } - /* If we didn't find any note, and we have a multi-reg hard + /* If we didn't find any note, or if we found a REG_DEAD note that + covers only part of the given reg, and we have a multi-reg hard register, then to be safe we must check for REG_DEAD notes for each register other than the first. They could have their own REG_DEAD notes lying around. */ - else if (note == 0 && regno < FIRST_PSEUDO_REGISTER + else if ((note == 0 + || (note != 0 + && (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) { int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); - int i; + int i, offset; rtx oldnotes = 0; - for (i = regno + 1; i < ourend; i++) + if (note) + offset = HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))); + else + offset = 1; + + for (i = regno + offset; i < ourend; i++) move_deaths (gen_rtx (REG, reg_raw_mode[i], i), maybe_kill_insn, from_cuid, to_insn, &oldnotes); } @@ -10955,6 +11009,14 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1) next_note = XEXP (note, 1); switch (REG_NOTE_KIND (note)) { + case REG_BR_PROB: + case REG_EXEC_COUNT: + /* Doesn't matter much where we put this, as long as it's somewhere. + It is preferable to keep these notes on branches, which is most + likely to be i3. */ + place = i3; + break; + case REG_UNUSED: /* Any clobbers for i3 may still exist, and so we must process REG_UNUSED notes from that insn.