X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Freload1.c;h=c469fb0761836d752cb5b343a0e1d199649a00d0;hb=cc6757ec825d05ba36419234bdcfea6bf03079d1;hp=4244b298308e961420380589ab302fb4c0363790;hpb=595d62e968f2f214fa217ab348994764a0ba26fd;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/reload1.c b/gcc/reload1.c index 4244b298308..c469fb07618 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -1,7 +1,7 @@ /* Reload pseudo regs into hard regs for insns that require hard regs. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, - Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. This file is part of GCC. @@ -888,16 +888,8 @@ reload (rtx first, int global) { int something_changed; int did_spill; - HOST_WIDE_INT starting_frame_size; - /* Round size of stack frame to stack_alignment_needed. This must be done - here because the stack size may be a part of the offset computation - for register elimination, and there might have been new stack slots - created in the last iteration of this loop. */ - if (cfun->stack_alignment_needed) - assign_stack_local (BLKmode, 0, cfun->stack_alignment_needed); - starting_frame_size = get_frame_size (); set_initial_elim_offsets (); @@ -964,6 +956,20 @@ reload (rtx first, int global) /* If we allocated another stack slot, redo elimination bookkeeping. */ if (starting_frame_size != get_frame_size ()) continue; + if (starting_frame_size && cfun->stack_alignment_needed) + { + /* If we have a stack frame, we must align it now. The + stack size may be a part of the offset computation for + register elimination. So if this changes the stack size, + then repeat the elimination bookkeeping. We don't + realign when there is no stack, as that will cause a + stack frame when none is needed should + STARTING_FRAME_OFFSET not be already aligned to + STACK_BOUNDARY. */ + assign_stack_local (BLKmode, 0, cfun->stack_alignment_needed); + if (starting_frame_size != get_frame_size ()) + continue; + } if (caller_save_needed) { @@ -995,7 +1001,7 @@ reload (rtx first, int global) HARD_REG_SET to_spill; CLEAR_HARD_REG_SET (to_spill); update_eliminables (&to_spill); - AND_COMPL_HARD_REG_SET(used_spill_regs, to_spill); + AND_COMPL_HARD_REG_SET (used_spill_regs, to_spill); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (TEST_HARD_REG_BIT (to_spill, i)) @@ -1860,7 +1866,7 @@ find_reload_regs (struct insn_chain *chain) if (! find_reg (chain, i)) { if (dump_file) - fprintf(dump_file, "reload failure for reload %d\n", r); + fprintf (dump_file, "reload failure for reload %d\n", r); spill_failure (chain->insn, rld[r].class); failure = 1; return; @@ -2542,6 +2548,30 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, case POST_INC: case PRE_DEC: case POST_DEC: + /* We do not support elimination of a register that is modified. + elimination_effects has already make sure that this does not + happen. */ + return x; + + case PRE_MODIFY: + case POST_MODIFY: + /* We do not support elimination of a register that is modified. + elimination_effects has already make sure that this does not + happen. The only remaining case we need to consider here is + that the increment value may be an eliminable register. */ + if (GET_CODE (XEXP (x, 1)) == PLUS + && XEXP (XEXP (x, 1), 0) == XEXP (x, 0)) + { + rtx new = eliminate_regs_1 (XEXP (XEXP (x, 1), 1), mem_mode, + insn, true); + + if (new != XEXP (XEXP (x, 1), 1)) + return gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (x, 0), + gen_rtx_PLUS (GET_MODE (x), + XEXP (x, 0), new)); + } + return x; + case STRICT_LOW_PART: case NEG: case NOT: case SIGN_EXTEND: case ZERO_EXTEND: @@ -2555,6 +2585,7 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, case CTZ: case POPCOUNT: case PARITY: + case BSWAP: new = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false); if (new != XEXP (x, 0)) return gen_rtx_fmt_e (code, GET_MODE (x), new); @@ -2736,6 +2767,14 @@ elimination_effects (rtx x, enum machine_mode mem_mode) case POST_DEC: case POST_MODIFY: case PRE_MODIFY: + /* If we modify the source of an elimination rule, disable it. */ + for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) + if (ep->from_rtx == XEXP (x, 0)) + ep->can_eliminate = 0; + + /* If we modify the target of an elimination rule by adding a constant, + update its offset. If we modify the target in any other way, we'll + have to disable the rule as well. */ for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) if (ep->to_rtx == XEXP (x, 0)) { @@ -2750,11 +2789,15 @@ elimination_effects (rtx x, enum machine_mode mem_mode) ep->offset += size; else if (code == PRE_INC || code == POST_INC) ep->offset -= size; - else if ((code == PRE_MODIFY || code == POST_MODIFY) - && GET_CODE (XEXP (x, 1)) == PLUS - && XEXP (x, 0) == XEXP (XEXP (x, 1), 0) - && CONSTANT_P (XEXP (XEXP (x, 1), 1))) - ep->offset -= INTVAL (XEXP (XEXP (x, 1), 1)); + else if (code == PRE_MODIFY || code == POST_MODIFY) + { + if (GET_CODE (XEXP (x, 1)) == PLUS + && XEXP (x, 0) == XEXP (XEXP (x, 1), 0) + && CONST_INT_P (XEXP (XEXP (x, 1), 1))) + ep->offset -= INTVAL (XEXP (XEXP (x, 1), 1)); + else + ep->can_eliminate = 0; + } } /* These two aren't unary operators. */ @@ -2775,6 +2818,7 @@ elimination_effects (rtx x, enum machine_mode mem_mode) case CTZ: case POPCOUNT: case PARITY: + case BSWAP: elimination_effects (XEXP (x, 0), mem_mode); return; @@ -3092,39 +3136,20 @@ eliminate_regs_in_insn (rtx insn, int replace) { rtx to_rtx = ep->to_rtx; offset += ep->offset; + offset = trunc_int_for_mode (offset, GET_MODE (reg)); if (GET_CODE (XEXP (plus_cst_src, 0)) == SUBREG) to_rtx = gen_lowpart (GET_MODE (XEXP (plus_cst_src, 0)), to_rtx); - if (offset == 0) - { - int num_clobbers; - /* We assume here that if we need a PARALLEL with - CLOBBERs for this assignment, we can do with the - MATCH_SCRATCHes that add_clobbers allocates. - There's not much we can do if that doesn't work. */ - PATTERN (insn) = gen_rtx_SET (VOIDmode, - SET_DEST (old_set), - to_rtx); - num_clobbers = 0; - INSN_CODE (insn) = recog (PATTERN (insn), insn, &num_clobbers); - if (num_clobbers) - { - rtvec vec = rtvec_alloc (num_clobbers + 1); - - vec->elem[0] = PATTERN (insn); - PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode, vec); - add_clobbers (PATTERN (insn), INSN_CODE (insn)); - } - gcc_assert (INSN_CODE (insn) >= 0); - } /* If we have a nonzero offset, and the source is already a simple REG, the following transformation would increase the cost of the insn by replacing a simple REG with (plus (reg sp) CST). So try only when we already had a PLUS before. */ - else if (plus_src) + if (offset == 0 || plus_src) { + rtx new_src = plus_constant (to_rtx, offset); + new_body = old_body; if (! replace) { @@ -3135,8 +3160,20 @@ eliminate_regs_in_insn (rtx insn, int replace) PATTERN (insn) = new_body; old_set = single_set (insn); - XEXP (SET_SRC (old_set), 0) = to_rtx; - XEXP (SET_SRC (old_set), 1) = GEN_INT (offset); + /* First see if this insn remains valid when we make the + change. If not, try to replace the whole pattern with + a simple set (this may help if the original insn was a + PARALLEL that was only recognized as single_set due to + REG_UNUSED notes). If this isn't valid either, keep + the INSN_CODE the same and let reload fix it up. */ + if (!validate_change (insn, &SET_SRC (old_set), new_src, 0)) + { + rtx new_pat = gen_rtx_SET (VOIDmode, + SET_DEST (old_set), new_src); + + if (!validate_change (insn, &PATTERN (insn), new_pat, 0)) + SET_SRC (old_set) = new_src; + } } else break; @@ -4792,6 +4829,51 @@ reload_reg_reaches_end_p (unsigned int regno, int opnum, enum reload_type type) } } + +/* Returns whether R1 and R2 are uniquely chained: the value of one + is used by the other, and that value is not used by any other + reload for this insn. This is used to partially undo the decision + made in find_reloads when in the case of multiple + RELOAD_FOR_OPERAND_ADDRESS reloads it converts all + RELOAD_FOR_OPADDR_ADDR reloads into RELOAD_FOR_OPERAND_ADDRESS + reloads. This code tries to avoid the conflict created by that + change. It might be cleaner to explicitly keep track of which + RELOAD_FOR_OPADDR_ADDR reload is associated with which + RELOAD_FOR_OPERAND_ADDRESS reload, rather than to try to detect + this after the fact. */ +static bool +reloads_unique_chain_p (int r1, int r2) +{ + int i; + + /* We only check input reloads. */ + if (! rld[r1].in || ! rld[r2].in) + return false; + + /* Avoid anything with output reloads. */ + if (rld[r1].out || rld[r2].out) + return false; + + /* "chained" means one reload is a component of the other reload, + not the same as the other reload. */ + if (rld[r1].opnum != rld[r2].opnum + || rtx_equal_p (rld[r1].in, rld[r2].in) + || rld[r1].optional || rld[r2].optional + || ! (reg_mentioned_p (rld[r1].in, rld[r2].in) + || reg_mentioned_p (rld[r2].in, rld[r1].in))) + return false; + + for (i = 0; i < n_reloads; i ++) + /* Look for input reloads that aren't our two */ + if (i != r1 && i != r2 && rld[i].in) + { + /* If our reload is mentioned at all, it isn't a simple chain. */ + if (reg_mentioned_p (rld[r1].in, rld[i].in)) + return false; + } + return true; +} + /* Return 1 if the reloads denoted by R1 and R2 cannot share a register. Return 0 otherwise. @@ -4840,7 +4922,8 @@ reloads_conflict (int r1, int r2) case RELOAD_FOR_OPERAND_ADDRESS: return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_INSN - || r2_type == RELOAD_FOR_OPERAND_ADDRESS); + || (r2_type == RELOAD_FOR_OPERAND_ADDRESS + && !reloads_unique_chain_p (r1, r2))); case RELOAD_FOR_OPADDR_ADDR: return (r2_type == RELOAD_FOR_INPUT @@ -5574,10 +5657,11 @@ choose_reload_regs (struct insn_chain *chain) else if (GET_CODE (rld[r].in_reg) == SUBREG && REG_P (SUBREG_REG (rld[r].in_reg))) { - byte = SUBREG_BYTE (rld[r].in_reg); regno = REGNO (SUBREG_REG (rld[r].in_reg)); if (regno < FIRST_PSEUDO_REGISTER) regno = subreg_regno (rld[r].in_reg); + else + byte = SUBREG_BYTE (rld[r].in_reg); mode = GET_MODE (rld[r].in_reg); } #ifdef AUTO_INC_DEC @@ -5598,7 +5682,16 @@ choose_reload_regs (struct insn_chain *chain) regno = subreg_regno (rld[r].in); #endif - if (regno >= 0 && reg_last_reload_reg[regno] != 0) + if (regno >= 0 + && reg_last_reload_reg[regno] != 0 +#ifdef CANNOT_CHANGE_MODE_CLASS + /* Verify that the register it's in can be used in + mode MODE. */ + && !REG_CANNOT_CHANGE_MODE_P (REGNO (reg_last_reload_reg[regno]), + GET_MODE (reg_last_reload_reg[regno]), + mode) +#endif + ) { enum reg_class class = rld[r].class, last_class; rtx last_reg = reg_last_reload_reg[regno]; @@ -5618,13 +5711,6 @@ choose_reload_regs (struct insn_chain *chain) if ((GET_MODE_SIZE (GET_MODE (last_reg)) >= GET_MODE_SIZE (need_mode)) -#ifdef CANNOT_CHANGE_MODE_CLASS - /* Verify that the register in "i" can be obtained - from LAST_REG. */ - && !REG_CANNOT_CHANGE_MODE_P (REGNO (last_reg), - GET_MODE (last_reg), - mode) -#endif && reg_reloaded_contents[i] == regno && TEST_HARD_REG_BIT (reg_reloaded_valid, i) && HARD_REGNO_MODE_OK (i, rld[r].mode) @@ -7506,6 +7592,23 @@ emit_reload_insns (struct insn_chain *chain) rtx out = ((rld[r].out && REG_P (rld[r].out)) ? rld[r].out : rld[r].out_reg); int nregno = REGNO (out); + + /* REG_RTX is now set or clobbered by the main instruction. + As the comment above explains, forget_old_reloads_1 only + sees the original instruction, and there is no guarantee + that the original instruction also clobbered REG_RTX. + For example, if find_reloads sees that the input side of + a matched operand pair dies in this instruction, it may + use the input register as the reload register. + + Calling forget_old_reloads_1 is a waste of effort if + REG_RTX is also the output register. + + If we know that REG_RTX holds the value of a pseudo + register, the code after the call will record that fact. */ + if (rld[r].reg_rtx && rld[r].reg_rtx != out) + forget_old_reloads_1 (rld[r].reg_rtx, NULL_RTX, NULL); + if (nregno >= FIRST_PSEUDO_REGISTER) { rtx src_reg, store_insn = NULL_RTX; @@ -7757,8 +7860,7 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type) if (insn) { /* Add a REG_EQUIV note so that find_equiv_reg can find it. */ - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_EQUIV, in, REG_NOTES (insn)); + set_unique_reg_note (insn, REG_EQUIV, in); return insn; } @@ -7767,7 +7869,7 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type) gen_reload (out, op1, opnum, type); insn = emit_insn (gen_add2_insn (out, op0)); - REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUIV, in, REG_NOTES (insn)); + set_unique_reg_note (insn, REG_EQUIV, in); } #ifdef SECONDARY_MEMORY_NEEDED @@ -7827,8 +7929,7 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type) insn = emit_insn_if_valid_for_reload (insn); if (insn) { - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_EQUIV, in, REG_NOTES (insn)); + set_unique_reg_note (insn, REG_EQUIV, in); return insn; } @@ -7924,6 +8025,9 @@ delete_output_reload (rtx insn, int j, int last_reload_reg) } } n_occurrences = count_occurrences (PATTERN (insn), reg, 0); + if (CALL_P (insn) && CALL_INSN_FUNCTION_USAGE (insn)) + n_occurrences += count_occurrences (CALL_INSN_FUNCTION_USAGE (insn), + reg, 0); if (substed) n_occurrences += count_occurrences (PATTERN (insn), eliminate_regs (substed, 0, @@ -8289,7 +8393,7 @@ inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount) emit_insn (gen_add2_insn (reloadreg, inc)); store = emit_insn (gen_move_insn (incloc, reloadreg)); if (GET_CODE (inc) == CONST_INT) - emit_insn (gen_add2_insn (reloadreg, GEN_INT (-INTVAL(inc)))); + emit_insn (gen_add2_insn (reloadreg, GEN_INT (-INTVAL (inc)))); else emit_insn (gen_sub2_insn (reloadreg, inc)); }