X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Freload1.c;h=88b89feb8ff110f5c23c304d101b83df15378c37;hb=4e970fe40fcb363c66c7d513409dbff8e35c611c;hp=a735cfed00fd337f471922557404f001e0770d68;hpb=00cb30dc08e9b6d5988e14797f58c2bfc298cfa1;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/reload1.c b/gcc/reload1.c index a735cfed00f..88b89feb8ff 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -87,7 +87,7 @@ static rtx *reg_last_reload_reg; /* Elt N nonzero if reg_last_reload_reg[N] has been set in this insn for an output reload that stores into reg N. */ -static char *reg_has_output_reload; +static regset_head reg_has_output_reload; /* Indicates which hard regs are reload-registers for an output reload in the current insn. */ @@ -112,7 +112,7 @@ rtx *reg_equiv_memory_loc; /* We allocate reg_equiv_memory_loc inside a varray so that the garbage collector can keep track of what is inside. */ -varray_type reg_equiv_memory_loc_varray; +VEC(rtx,gc) *reg_equiv_memory_loc_vec; /* Element N is the address of stack slot to which pseudo reg N is equivalent. This is used when the address is not valid as a memory address @@ -123,6 +123,10 @@ rtx *reg_equiv_address; or zero if pseudo reg N is not equivalent to a memory slot. */ rtx *reg_equiv_mem; +/* Element N is an EXPR_LIST of REG_EQUIVs containing MEMs with + alternate representations of the location of pseudo reg N. */ +rtx *reg_equiv_alt_mem_list; + /* Widest width in which each pseudo reg is referred to (via subreg). */ static unsigned int *reg_max_ref_width; @@ -404,6 +408,7 @@ static void count_pseudo (int); static void order_regs_for_reload (struct insn_chain *); static void reload_as_needed (int); static void forget_old_reloads_1 (rtx, rtx, void *); +static void forget_marked_reloads (regset); static int reload_reg_class_lower (const void *, const void *); static void mark_reload_reg_in_use (unsigned int, int, enum reload_type, enum machine_mode); @@ -496,7 +501,6 @@ init_reload (void) INIT_REG_SET (&spilled_pseudos); INIT_REG_SET (&pseudos_counted); - VARRAY_RTX_INIT (reg_equiv_memory_loc_varray, 0, "reg_equiv_memory_loc"); } /* List of insn chains that are currently unused. */ @@ -704,6 +708,7 @@ reload (rtx first, int global) reg_equiv_constant = XCNEWVEC (rtx, max_regno); reg_equiv_invariant = XCNEWVEC (rtx, max_regno); reg_equiv_mem = XCNEWVEC (rtx, max_regno); + reg_equiv_alt_mem_list = XCNEWVEC (rtx, max_regno); reg_equiv_address = XCNEWVEC (rtx, max_regno); reg_max_ref_width = XCNEWVEC (unsigned int, max_regno); reg_old_renumber = XCNEWVEC (short, max_regno); @@ -990,6 +995,8 @@ 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); + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (TEST_HARD_REG_BIT (to_spill, i)) { @@ -1160,6 +1167,20 @@ reload (rtx first, int global) { rtx *pnote; + /* Clean up invalid ASMs so that they don't confuse later passes. + See PR 21299. */ + if (asm_noperands (PATTERN (insn)) >= 0) + { + extract_insn (insn); + if (!constrain_operands (1)) + { + error_for_asm (insn, + "% operand has impossible constraints"); + delete_insn (insn); + continue; + } + } + if (CALL_P (insn)) replace_pseudos_in (& CALL_INSN_FUNCTION_USAGE (insn), VOIDmode, CALL_INSN_FUNCTION_USAGE (insn)); @@ -1251,7 +1272,7 @@ reload (rtx first, int global) free (reg_equiv_invariant); reg_equiv_constant = 0; reg_equiv_invariant = 0; - VARRAY_GROW (reg_equiv_memory_loc_varray, 0); + VEC_free (rtx, gc, reg_equiv_memory_loc_vec); reg_equiv_memory_loc = 0; if (offsets_known_at) @@ -1259,6 +1280,11 @@ reload (rtx first, int global) if (offsets_at) free (offsets_at); + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (reg_equiv_alt_mem_list[i]) + free_EXPR_LIST_list (®_equiv_alt_mem_list[i]); + free (reg_equiv_alt_mem_list); + free (reg_equiv_mem); reg_equiv_init = 0; free (reg_equiv_address); @@ -1834,7 +1860,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; @@ -1970,8 +1996,11 @@ alter_reg (int i, int from_reg) && reg_equiv_memory_loc[i] == 0) { rtx x; + enum machine_mode mode = GET_MODE (regno_reg_rtx[i]); unsigned int inherent_size = PSEUDO_REGNO_BYTES (i); + unsigned int inherent_align = GET_MODE_ALIGNMENT (mode); unsigned int total_size = MAX (inherent_size, reg_max_ref_width[i]); + unsigned int min_align = reg_max_ref_width[i] * BITS_PER_UNIT; int adjust = 0; /* Each pseudo reg has an inherent size which comes from its own mode, @@ -1985,8 +2014,9 @@ alter_reg (int i, int from_reg) if (from_reg == -1) { /* No known place to spill from => no slot to reuse. */ - x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size, - inherent_size == total_size ? 0 : -1); + x = assign_stack_local (mode, total_size, + min_align > inherent_align + || total_size > inherent_size ? -1 : 0); if (BYTES_BIG_ENDIAN) /* Cancel the big-endian correction done in assign_stack_local. Get the address of the beginning of the slot. @@ -2002,7 +2032,8 @@ alter_reg (int i, int from_reg) else if (spill_stack_slot[from_reg] != 0 && spill_stack_slot_width[from_reg] >= total_size && (GET_MODE_SIZE (GET_MODE (spill_stack_slot[from_reg])) - >= inherent_size)) + >= inherent_size) + && MEM_ALIGN (spill_stack_slot[from_reg]) >= min_align) x = spill_stack_slot[from_reg]; /* Allocate a bigger slot. */ @@ -2010,7 +2041,6 @@ alter_reg (int i, int from_reg) { /* Compute maximum size needed, both for inherent size and for total size. */ - enum machine_mode mode = GET_MODE (regno_reg_rtx[i]); rtx stack_slot; if (spill_stack_slot[from_reg]) @@ -2020,11 +2050,14 @@ alter_reg (int i, int from_reg) mode = GET_MODE (spill_stack_slot[from_reg]); if (spill_stack_slot_width[from_reg] > total_size) total_size = spill_stack_slot_width[from_reg]; + if (MEM_ALIGN (spill_stack_slot[from_reg]) > min_align) + min_align = MEM_ALIGN (spill_stack_slot[from_reg]); } /* Make a slot with that size. */ x = assign_stack_local (mode, total_size, - inherent_size == total_size ? 0 : -1); + min_align > inherent_align + || total_size > inherent_size ? -1 : 0); stack_slot = x; /* All pseudos mapped to this slot can alias each other. */ @@ -2522,6 +2555,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); @@ -2742,6 +2776,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; @@ -3802,7 +3837,8 @@ scan_paradoxical_subregs (rtx x) case SUBREG: if (REG_P (SUBREG_REG (x)) - && GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) + && (GET_MODE_SIZE (GET_MODE (x)) + > reg_max_ref_width[REGNO (SUBREG_REG (x))])) reg_max_ref_width[REGNO (SUBREG_REG (x))] = GET_MODE_SIZE (GET_MODE (x)); return; @@ -3877,7 +3913,7 @@ reload_as_needed (int live_known) memset (spill_reg_rtx, 0, sizeof spill_reg_rtx); memset (spill_reg_store, 0, sizeof spill_reg_store); reg_last_reload_reg = XCNEWVEC (rtx, max_regno); - reg_has_output_reload = XNEWVEC (char, max_regno); + INIT_REG_SET (®_has_output_reload); CLEAR_HARD_REG_SET (reg_reloaded_valid); CLEAR_HARD_REG_SET (reg_reloaded_call_part_clobbered); @@ -3896,7 +3932,9 @@ reload_as_needed (int live_known) else if (INSN_P (insn)) { - rtx oldpat = copy_rtx (PATTERN (insn)); + regset_head regs_to_forget; + INIT_REG_SET (®s_to_forget); + note_stores (PATTERN (insn), forget_old_reloads_1, ®s_to_forget); /* If this is a USE and CLOBBER of a MEM, ensure that any references to eliminable registers have been removed. */ @@ -3917,6 +3955,7 @@ reload_as_needed (int live_known) if (NOTE_P (insn)) { update_eliminable_offsets (); + CLEAR_REG_SET (®s_to_forget); continue; } } @@ -3937,7 +3976,7 @@ reload_as_needed (int live_known) rtx's for those pseudo regs. */ else { - memset (reg_has_output_reload, 0, max_regno); + CLEAR_REG_SET (®_has_output_reload); CLEAR_HARD_REG_SET (reg_is_output_reload); find_reloads (insn, 1, spill_indirect_levels, live_known, @@ -4003,7 +4042,8 @@ reload_as_needed (int live_known) for this insn in order to be stored in (obeying register constraints). That is correct; such reload registers ARE still valid. */ - note_stores (oldpat, forget_old_reloads_1, NULL); + forget_marked_reloads (®s_to_forget); + CLEAR_REG_SET (®s_to_forget); /* There may have been CLOBBER insns placed after INSN. So scan between INSN and NEXT and use them to forget old reloads. */ @@ -4090,7 +4130,8 @@ reload_as_needed (int live_known) the reload for inheritance. */ SET_HARD_REG_BIT (reg_is_output_reload, REGNO (reload_reg)); - reg_has_output_reload[REGNO (XEXP (in_reg, 0))] = 1; + SET_REGNO_REG_SET (®_has_output_reload, + REGNO (XEXP (in_reg, 0))); } else forget_old_reloads_1 (XEXP (in_reg, 0), NULL_RTX, @@ -4106,7 +4147,8 @@ reload_as_needed (int live_known) { SET_HARD_REG_BIT (reg_is_output_reload, REGNO (rld[i].reg_rtx)); - reg_has_output_reload[REGNO (XEXP (in_reg, 0))] = 1; + SET_REGNO_REG_SET (®_has_output_reload, + REGNO (XEXP (in_reg, 0))); } } } @@ -4144,7 +4186,7 @@ reload_as_needed (int live_known) /* Clean up. */ free (reg_last_reload_reg); - free (reg_has_output_reload); + CLEAR_REG_SET (®_has_output_reload); } /* Discard all record of any value reloaded from X, @@ -4152,14 +4194,18 @@ reload_as_needed (int live_known) unless X is an output reload reg of the current insn. X may be a hard reg (the reload reg) - or it may be a pseudo reg that was reloaded from. */ + or it may be a pseudo reg that was reloaded from. + + When DATA is non-NULL just mark the registers in regset + to be forgotten later. */ static void forget_old_reloads_1 (rtx x, rtx ignored ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) + void *data) { unsigned int regno; unsigned int nr; + regset regs = (regset) data; /* note_stores does give us subregs of hard regs, subreg_regno_offset requires a hard reg. */ @@ -4187,26 +4233,58 @@ forget_old_reloads_1 (rtx x, rtx ignored ATTRIBUTE_UNUSED, This can happen if a block-local pseudo is allocated to that reg and it wasn't spilled because this block's total need is 0. Then some insn might have an optional reload and use this reg. */ - for (i = 0; i < nr; i++) - /* But don't do this if the reg actually serves as an output - reload reg in the current instruction. */ + if (!regs) + for (i = 0; i < nr; i++) + /* But don't do this if the reg actually serves as an output + reload reg in the current instruction. */ + if (n_reloads == 0 + || ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i)) + { + CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i); + CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, regno + i); + spill_reg_store[regno + i] = 0; + } + } + + if (regs) + while (nr-- > 0) + SET_REGNO_REG_SET (regs, regno + nr); + else + { + /* Since value of X has changed, + forget any value previously copied from it. */ + + while (nr-- > 0) + /* But don't forget a copy if this is the output reload + that establishes the copy's validity. */ if (n_reloads == 0 - || ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i)) + || !REGNO_REG_SET_P (®_has_output_reload, regno + nr)) + reg_last_reload_reg[regno + nr] = 0; + } +} + +/* Forget the reloads marked in regset by previous function. */ +static void +forget_marked_reloads (regset regs) +{ + unsigned int reg; + reg_set_iterator rsi; + EXECUTE_IF_SET_IN_REG_SET (regs, 0, reg, rsi) + { + if (reg < FIRST_PSEUDO_REGISTER + /* But don't do this if the reg actually serves as an output + reload reg in the current instruction. */ + && (n_reloads == 0 + || ! TEST_HARD_REG_BIT (reg_is_output_reload, reg))) { - CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i); - CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, regno + i); - spill_reg_store[regno + i] = 0; + CLEAR_HARD_REG_BIT (reg_reloaded_valid, reg); + CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, reg); + spill_reg_store[reg] = 0; } + if (n_reloads == 0 + || !REGNO_REG_SET_P (®_has_output_reload, reg)) + reg_last_reload_reg[reg] = 0; } - - /* Since value of X has changed, - forget any value previously copied from it. */ - - while (nr-- > 0) - /* But don't forget a copy if this is the output reload - that establishes the copy's validity. */ - if (n_reloads == 0 || reg_has_output_reload[regno + nr] == 0) - reg_last_reload_reg[regno + nr] = 0; } /* The following HARD_REG_SETs indicate when each hard register is @@ -4716,6 +4794,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. @@ -4764,7 +4887,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 @@ -5505,10 +5629,7 @@ choose_reload_regs (struct insn_chain *chain) mode = GET_MODE (rld[r].in_reg); } #ifdef AUTO_INC_DEC - else if ((GET_CODE (rld[r].in_reg) == PRE_INC - || GET_CODE (rld[r].in_reg) == PRE_DEC - || GET_CODE (rld[r].in_reg) == POST_INC - || GET_CODE (rld[r].in_reg) == POST_DEC) + else if (GET_RTX_CLASS (GET_CODE (rld[r].in_reg)) == RTX_AUTOINC && REG_P (XEXP (rld[r].in_reg, 0))) { regno = REGNO (XEXP (rld[r].in_reg, 0)); @@ -6037,7 +6158,8 @@ choose_reload_regs (struct insn_chain *chain) nr = hard_regno_nregs[nregno][rld[r].mode]; while (--nr >= 0) - reg_has_output_reload[nregno + nr] = 1; + SET_REGNO_REG_SET (®_has_output_reload, + nregno + nr); if (i >= 0) { @@ -7227,7 +7349,7 @@ emit_reload_insns (struct insn_chain *chain) if (REG_P (reg) && REGNO (reg) >= FIRST_PSEUDO_REGISTER - && ! reg_has_output_reload[REGNO (reg)]) + && !REGNO_REG_SET_P (®_has_output_reload, REGNO (reg))) { int nregno = REGNO (reg); @@ -7338,9 +7460,11 @@ emit_reload_insns (struct insn_chain *chain) && rld[r].in != 0 && ((REG_P (rld[r].in) && REGNO (rld[r].in) >= FIRST_PSEUDO_REGISTER - && ! reg_has_output_reload[REGNO (rld[r].in)]) + && !REGNO_REG_SET_P (®_has_output_reload, + REGNO (rld[r].in))) || (REG_P (rld[r].in_reg) - && ! reg_has_output_reload[REGNO (rld[r].in_reg)])) + && !REGNO_REG_SET_P (®_has_output_reload, + REGNO (rld[r].in_reg)))) && ! reg_set_p (rld[r].reg_rtx, PATTERN (insn))) { int nregno; @@ -7498,7 +7622,8 @@ emit_reload_insns (struct insn_chain *chain) /* We have to set reg_has_output_reload here, or else forget_old_reloads_1 will clear reg_last_reload_reg right away. */ - reg_has_output_reload[nregno] = 1; + SET_REGNO_REG_SET (®_has_output_reload, + nregno); } } else @@ -7759,7 +7884,11 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type) } /* If IN is a simple operand, use gen_move_insn. */ else if (OBJECT_P (in) || GET_CODE (in) == SUBREG) - emit_insn (gen_move_insn (out, in)); + { + tem = emit_insn (gen_move_insn (out, in)); + /* IN may contain a LABEL_REF, if so add a REG_LABEL note. */ + mark_jump_label (in, tem, 0); + } #ifdef HAVE_reload_load_address else if (HAVE_reload_load_address) @@ -7847,6 +7976,11 @@ delete_output_reload (rtx insn, int j, int last_reload_reg) n_occurrences += count_occurrences (PATTERN (insn), eliminate_regs (substed, 0, NULL_RTX), 0); + for (i1 = reg_equiv_alt_mem_list [REGNO (reg)]; i1; i1 = XEXP (i1, 1)) + { + gcc_assert (!rtx_equal_p (XEXP (i1, 0), substed)); + n_occurrences += count_occurrences (PATTERN (insn), XEXP (i1, 0), 0); + } if (n_occurrences > n_inherited) return; @@ -8113,15 +8247,16 @@ static rtx inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount) { /* REG or MEM to be copied and incremented. */ - rtx incloc = XEXP (value, 0); + rtx incloc = find_replacement (&XEXP (value, 0)); /* Nonzero if increment after copying. */ - int post = (GET_CODE (value) == POST_DEC || GET_CODE (value) == POST_INC); + int post = (GET_CODE (value) == POST_DEC || GET_CODE (value) == POST_INC + || GET_CODE (value) == POST_MODIFY); rtx last; rtx inc; rtx add_insn; int code; rtx store; - rtx real_in = in == value ? XEXP (in, 0) : in; + rtx real_in = in == value ? incloc : in; /* No hard register is equivalent to this register after inc/dec operation. If REG_LAST_RELOAD_REG were nonzero, @@ -8130,10 +8265,18 @@ inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount) if (REG_P (incloc)) reg_last_reload_reg[REGNO (incloc)] = 0; - if (GET_CODE (value) == PRE_DEC || GET_CODE (value) == POST_DEC) - inc_amount = -inc_amount; + if (GET_CODE (value) == PRE_MODIFY || GET_CODE (value) == POST_MODIFY) + { + gcc_assert (GET_CODE (XEXP (value, 1)) == PLUS); + inc = find_replacement (&XEXP (XEXP (value, 1), 1)); + } + else + { + if (GET_CODE (value) == PRE_DEC || GET_CODE (value) == POST_DEC) + inc_amount = -inc_amount; - inc = GEN_INT (inc_amount); + inc = GEN_INT (inc_amount); + } /* If this is post-increment, first copy the location to the reload reg. */ if (post && real_in != reloadreg) @@ -8193,7 +8336,10 @@ 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)); - emit_insn (gen_add2_insn (reloadreg, GEN_INT (-inc_amount))); + if (GET_CODE (inc) == CONST_INT) + emit_insn (gen_add2_insn (reloadreg, GEN_INT (-INTVAL (inc)))); + else + emit_insn (gen_sub2_insn (reloadreg, inc)); } return store;