X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Freload1.c;h=504c9e09049c2ab24154ebbc79b30077f8ed191c;hp=ce049220608804b4d2ebf89707f7cfa8b67b9a0e;hb=1667266b661abacc0476fddcbbccecebf986db91;hpb=98155838dbd82b97bb7bb16dfcbf98fa2ab27ca9 diff --git a/gcc/reload1.c b/gcc/reload1.c index ce049220608..504c9e09049 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -1,6 +1,6 @@ /* 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, 2007, 2008, 2009 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -37,15 +37,14 @@ along with GCC; see the file COPYING3. If not see #include "regs.h" #include "addresses.h" #include "basic-block.h" +#include "df.h" #include "reload.h" #include "recog.h" #include "output.h" -#include "real.h" #include "toplev.h" #include "except.h" #include "tree.h" #include "ira.h" -#include "df.h" #include "target.h" #include "emit-rtl.h" @@ -378,6 +377,21 @@ static int first_label_num; static char *offsets_known_at; static HOST_WIDE_INT (*offsets_at)[NUM_ELIMINABLE_REGS]; +/* Stack of addresses where an rtx has been changed. We can undo the + changes by popping items off the stack and restoring the original + value at each location. + + We use this simplistic undo capability rather than copy_rtx as copy_rtx + will not make a deep copy of a normally sharable rtx, such as + (const (plus (symbol_ref) (const_int))). If such an expression appears + as R1 in gen_reload_chain_without_interm_reg_p, then a shared + rtx expression would be changed. See PR 42431. */ + +typedef rtx *rtx_p; +DEF_VEC_P(rtx_p); +DEF_VEC_ALLOC_P(rtx_p,heap); +static VEC(rtx_p,heap) *substitute_stack; + /* Number of labels in the current function. */ static int num_labels; @@ -638,7 +652,7 @@ has_nonexceptional_receiver (void) /* If we're not optimizing, then just err on the safe side. */ if (!optimize) return true; - + /* First determine which blocks can reach exit via normal paths. */ tos = worklist = XNEWVEC (basic_block, n_basic_blocks + 1); @@ -648,7 +662,7 @@ has_nonexceptional_receiver (void) /* Place the exit block on our worklist. */ EXIT_BLOCK_PTR->flags |= BB_REACHABLE; *tos++ = EXIT_BLOCK_PTR; - + /* Iterate: find everything reachable from what we've already seen. */ while (tos != worklist) { @@ -687,6 +701,8 @@ has_nonexceptional_receiver (void) static int something_needs_elimination; /* Set during calculate_needs if an insn needs an operand changed. */ static int something_needs_operands_changed; +/* Set by alter_regs if we spilled a register to the stack. */ +static bool something_was_spilled; /* Nonzero means we couldn't get enough spill regs. */ static int failure; @@ -900,7 +916,7 @@ reload (rtx first, int global) temp_pseudo_reg_arr = XNEWVEC (int, max_regno - LAST_VIRTUAL_REGISTER - 1); for (n = 0, i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++) temp_pseudo_reg_arr[n++] = i; - + if (ira_conflicts_p) /* Ask IRA to order pseudo-registers for better stack slot sharing. */ @@ -966,6 +982,7 @@ reload (rtx first, int global) HOST_WIDE_INT starting_frame_size; starting_frame_size = get_frame_size (); + something_was_spilled = false; set_initial_elim_offsets (); set_initial_label_offsets (); @@ -1031,7 +1048,7 @@ reload (rtx first, int global) setup_save_areas (); /* If we allocated another stack slot, redo elimination bookkeeping. */ - if (starting_frame_size != get_frame_size ()) + if (something_was_spilled || starting_frame_size != get_frame_size ()) continue; if (starting_frame_size && crtl->stack_alignment_needed) { @@ -1069,11 +1086,11 @@ reload (rtx first, int global) /* If we allocated any new memory locations, make another pass since it might have changed elimination offsets. */ - if (starting_frame_size != get_frame_size ()) + if (something_was_spilled || starting_frame_size != get_frame_size ()) something_changed = 1; /* Even if the frame size remained the same, we might still have - changed elimination offsets, e.g. if find_reloads called + changed elimination offsets, e.g. if find_reloads called force_const_mem requiring the back end to allocate a constant pool base register that needs to be saved on the stack. */ else if (!verify_initial_elim_offsets ()) @@ -1184,7 +1201,7 @@ reload (rtx first, int global) if (! frame_pointer_needed) FOR_EACH_BB (bb) bitmap_clear_bit (df_get_live_in (bb), HARD_FRAME_POINTER_REGNUM); - + /* Come here (with failure set nonzero) if we can't get enough spill regs. */ failed: @@ -1448,6 +1465,8 @@ reload (rtx first, int global) REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = BITS_PER_UNIT; #endif + VEC_free (rtx_p, heap, substitute_stack); + return failure; } @@ -2206,6 +2225,8 @@ alter_reg (int i, int from_reg, bool dont_share_p) unsigned int min_align = reg_max_ref_width[i] * BITS_PER_UNIT; int adjust = 0; + something_was_spilled = true; + if (ira_conflicts_p) { /* Mark the spill for IRA. */ @@ -2570,7 +2591,7 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, else if (reg_renumber && reg_renumber[regno] < 0 && reg_equiv_invariant && reg_equiv_invariant[regno]) { - if (may_use_invariant) + if (may_use_invariant || (insn && DEBUG_INSN_P (insn))) return eliminate_regs_1 (copy_rtx (reg_equiv_invariant[regno]), mem_mode, insn, true); /* There exists at least one use of REGNO that cannot be @@ -2685,9 +2706,11 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, if (ep->from_rtx == XEXP (x, 0) && ep->can_eliminate) { if (! mem_mode - /* Refs inside notes don't count for this purpose. */ + /* Refs inside notes or in DEBUG_INSNs don't count for + this purpose. */ && ! (insn != 0 && (GET_CODE (insn) == EXPR_LIST - || GET_CODE (insn) == INSN_LIST))) + || GET_CODE (insn) == INSN_LIST + || DEBUG_INSN_P (insn)))) ep->ref_outside_mem = 1; return @@ -2863,6 +2886,9 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, return x; case CLOBBER: + gcc_assert (insn && DEBUG_INSN_P (insn)); + break; + case ASM_OPERANDS: case SET: gcc_unreachable (); @@ -3199,6 +3225,9 @@ eliminate_regs_in_insn (rtx insn, int replace) || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC || GET_CODE (PATTERN (insn)) == ASM_INPUT || DEBUG_INSN_P (insn)); + if (DEBUG_INSN_P (insn)) + INSN_VAR_LOCATION_LOC (insn) + = eliminate_regs (INSN_VAR_LOCATION_LOC (insn), VOIDmode, insn); return 0; } @@ -3375,7 +3404,7 @@ eliminate_regs_in_insn (rtx insn, int replace) /* 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 + 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)) @@ -3532,7 +3561,10 @@ eliminate_regs_in_insn (rtx insn, int replace) { /* Restore the old body. */ for (i = 0; i < recog_data.n_operands; i++) - *recog_data.operand_loc[i] = orig_operand[i]; + /* Restoring a top-level match_parallel would clobber the new_body + we installed in the insn. */ + if (recog_data.operand_loc[i] != &PATTERN (insn)) + *recog_data.operand_loc[i] = orig_operand[i]; for (i = 0; i < recog_data.n_dups; i++) *recog_data.dup_loc[i] = orig_operand[(int) recog_data.dup_num[i]]; } @@ -3750,7 +3782,7 @@ update_eliminables (HARD_REG_SET *pset) struct elim_table *ep; for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if ((ep->from == HARD_FRAME_POINTER_REGNUM + if ((ep->from == HARD_FRAME_POINTER_REGNUM && targetm.frame_pointer_required ()) #ifdef ELIMINABLE_REGS || ! targetm.can_eliminate (ep->from, ep->to) @@ -3861,7 +3893,7 @@ init_elim_table (void) ep->can_eliminate = ep->can_eliminate_previous = (targetm.can_eliminate (ep->from, ep->to) && ! (ep->to == STACK_POINTER_REGNUM - && frame_pointer_needed + && frame_pointer_needed && (! SUPPORTS_STACK_ALIGNMENT || ! stack_realign_fp))); } @@ -3960,7 +3992,7 @@ finish_spills (int global) in pseudo_previous_regs so we avoid reallocating it to the same hard reg in a later pass. */ gcc_assert (reg_renumber[i] >= 0); - + SET_HARD_REG_BIT (pseudo_previous_regs[i], reg_renumber[i]); /* Mark it as no longer having a hard register home. */ reg_renumber[i] = -1; @@ -4253,7 +4285,7 @@ reload_as_needed (int live_known) /* Merge any reloads that we didn't combine for fear of increasing the number of spill registers needed but now discover can be safely merged. */ - if (SMALL_REGISTER_CLASSES) + if (targetm.small_register_classes_for_mode_p (VOIDmode)) merge_assigned_reloads (insn); /* Generate the insns to reload operands into or out of @@ -4482,7 +4514,7 @@ 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. */ @@ -5139,9 +5171,8 @@ reloads_unique_chain_p (int r1, int r2) return true; } - /* The recursive function change all occurrences of WHAT in *WHERE - onto REPL. */ + to REPL. */ static void substitute (rtx *where, const_rtx what, rtx repl) { @@ -5154,6 +5185,8 @@ substitute (rtx *where, const_rtx what, rtx repl) if (*where == what || rtx_equal_p (*where, what)) { + /* Record the location of the changed rtx. */ + VEC_safe_push (rtx_p, heap, substitute_stack, where); *where = repl; return; } @@ -5201,7 +5234,9 @@ substitute (rtx *where, const_rtx what, rtx repl) static bool gen_reload_chain_without_interm_reg_p (int r1, int r2) { - bool result; + /* Assume other cases in gen_reload are not possible for + chain reloads or do need an intermediate hard registers. */ + bool result = true; int regno, n, code; rtx out, in, tem, insn; rtx last = get_last_insn (); @@ -5217,7 +5252,7 @@ gen_reload_chain_without_interm_reg_p (int r1, int r2) regno = rld[r1].regno >= 0 ? rld[r1].regno : rld[r2].regno; gcc_assert (regno >= 0); out = gen_rtx_REG (rld[r1].mode, regno); - in = copy_rtx (rld[r1].in); + in = rld[r1].in; substitute (&in, rld[r2].in, gen_rtx_REG (rld[r2].mode, regno)); /* If IN is a paradoxical SUBREG, remove it and try to put the @@ -5249,14 +5284,18 @@ gen_reload_chain_without_interm_reg_p (int r1, int r2) reload has completed. */ result = constrain_operands (1); } - + delete_insns_since (last); - return result; } - - /* It looks like other cases in gen_reload are not possible for - chain reloads or do need an intermediate hard registers. */ - return true; + + /* Restore the original value at each changed address within R1. */ + while (!VEC_empty (rtx_p, substitute_stack)) + { + rtx *where = VEC_pop (rtx_p, substitute_stack); + *where = rld[r2].in; + } + + return result; } /* Return 1 if the reloads denoted by R1 and R2 cannot share a register. @@ -6632,10 +6671,11 @@ deallocate_reload_reg (int r) reload_spill_index[r] = -1; } -/* If SMALL_REGISTER_CLASSES is nonzero, we may not have merged two - reloads of the same item for fear that we might not have enough reload - registers. However, normally they will get the same reload register - and hence actually need not be loaded twice. +/* If the small_register_classes_for_mode_p target hook returns true for + some machine modes, we may not have merged two reloads of the same item + for fear that we might not have enough reload registers. However, + normally they will get the same reload register and hence actually need + not be loaded twice. Here we check for the most common case of this phenomenon: when we have a number of reloads for the same object, each of which were allocated @@ -8124,7 +8164,7 @@ emit_reload_insns (struct insn_chain *chain) SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + k); if (HARD_REGNO_CALL_PART_CLOBBERED (src_regno + k, mode)) - SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, + SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, src_regno + k); else CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, @@ -8136,7 +8176,7 @@ emit_reload_insns (struct insn_chain *chain) CLEAR_HARD_REG_BIT (reg_reloaded_died, src_regno); } reg_last_reload_reg[out_regno] = src_reg; - /* We have to set reg_has_output_reload here, or else + /* We have to set reg_has_output_reload here, or else forget_old_reloads_1 will clear reg_last_reload_reg right away. */ SET_REGNO_REG_SET (®_has_output_reload, @@ -8970,7 +9010,7 @@ fixup_abnormal_edges (void) } /* It may be that we don't find any such trapping insn. In this - case we discovered quite late that the insn that had been + case we discovered quite late that the insn that had been marked as can_throw_internal in fact couldn't trap at all. So we should in fact delete the EH edges out of the block. */ else