X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;ds=sidebyside;f=gcc%2Freload1.c;h=06df026d81a1e6318d5321a6ffb2e6484f7b7f11;hb=44fcef54e407a058a5a1ed8f9e372deb3bff9d10;hp=3eb20b02ff80bedb030ac556938c06babf153aae;hpb=7151fd0e46078735d19ba3c266e02bc66e5bcc84;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/reload1.c b/gcc/reload1.c index 3eb20b02ff8..06df026d81a 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 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GCC. @@ -268,15 +268,15 @@ enum insn_code reload_out_optab[NUM_MACHINE_MODES]; /* This obstack is used for allocation of rtl during register elimination. The allocated storage can be freed once find_reloads has processed the insn. */ -struct obstack reload_obstack; +static struct obstack reload_obstack; /* Points to the beginning of the reload_obstack. All insn_chain structures are allocated first. */ -char *reload_startobj; +static char *reload_startobj; /* The point after all insn_chain structures. Used to quickly deallocate memory allocated in copy_reloads during calculate_needs_all_insns. */ -char *reload_firstobj; +static char *reload_firstobj; /* This points before all local rtl generated by register elimination. Used to quickly free all memory after processing one insn. */ @@ -390,7 +390,6 @@ static void init_elim_table (void); static void update_eliminables (HARD_REG_SET *); static void spill_hard_reg (unsigned int, int); static int finish_spills (int); -static void ior_hard_reg_set (HARD_REG_SET *, HARD_REG_SET *); static void scan_paradoxical_subregs (rtx); static void count_pseudo (int); static void order_regs_for_reload (struct insn_chain *); @@ -431,6 +430,8 @@ static rtx inc_for_reload (rtx, rtx, rtx, int); static void add_auto_inc_notes (rtx, rtx); #endif static void copy_eh_notes (rtx, rtx); +static int reloads_conflict (int, int); +static rtx gen_reload (rtx, rtx, int, enum reload_type); /* Initialize the reload pass once per compilation. */ @@ -523,29 +524,28 @@ void compute_use_by_pseudos (HARD_REG_SET *to, regset from) { unsigned int regno; + reg_set_iterator rsi; - EXECUTE_IF_SET_IN_REG_SET - (from, FIRST_PSEUDO_REGISTER, regno, - { - int r = reg_renumber[regno]; - int nregs; - - if (r < 0) - { - /* reload_combine uses the information from - BASIC_BLOCK->global_live_at_start, which might still - contain registers that have not actually been allocated - since they have an equivalence. */ - if (! reload_completed) - abort (); - } - else - { - nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)]; - while (nregs-- > 0) - SET_HARD_REG_BIT (*to, r + nregs); - } - }); + EXECUTE_IF_SET_IN_REG_SET (from, FIRST_PSEUDO_REGISTER, regno, rsi) + { + int r = reg_renumber[regno]; + int nregs; + + if (r < 0) + { + /* reload_combine uses the information from + BASIC_BLOCK->global_live_at_start, which might still + contain registers that have not actually been allocated + since they have an equivalence. */ + gcc_assert (reload_completed); + } + else + { + nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)]; + while (nregs-- > 0) + SET_HARD_REG_BIT (*to, r + nregs); + } + } } /* Replace all pseudos found in LOC with their corresponding @@ -584,11 +584,12 @@ replace_pseudos_in (rtx *loc, enum machine_mode mem_mode, rtx usage) *loc = reg_equiv_mem[regno]; else if (reg_equiv_address[regno]) *loc = gen_rtx_MEM (GET_MODE (x), reg_equiv_address[regno]); - else if (!REG_P (regno_reg_rtx[regno]) - || REGNO (regno_reg_rtx[regno]) != regno) - *loc = regno_reg_rtx[regno]; else - abort (); + { + gcc_assert (!REG_P (regno_reg_rtx[regno]) + || REGNO (regno_reg_rtx[regno]) != regno); + *loc = regno_reg_rtx[regno]; + } return; } @@ -614,7 +615,7 @@ replace_pseudos_in (rtx *loc, enum machine_mode mem_mode, rtx usage) /* Set during calculate_needs if an insn needs register elimination. */ static int something_needs_elimination; /* Set during calculate_needs if an insn needs an operand changed. */ -int something_needs_operands_changed; +static int something_needs_operands_changed; /* Nonzero means we couldn't get enough spill regs. */ static int failure; @@ -681,17 +682,6 @@ reload (rtx first, int global) if (! call_used_regs[i] && ! fixed_regs[i] && ! LOCAL_REGNO (i)) regs_ever_live[i] = 1; -#ifdef NON_SAVING_SETJMP - /* A function that calls setjmp should save and restore all the - call-saved registers on a system where longjmp clobbers them. */ - if (NON_SAVING_SETJMP && current_function_calls_setjmp) - { - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (! call_used_regs[i]) - regs_ever_live[i] = 1; - } -#endif - /* Find all the pseudo registers that didn't get hard regs but do have known equivalent constants or memory slots. These include parameters (known equivalent to parameter slots) @@ -750,8 +740,20 @@ reload (rtx first, int global) that is not a legitimate memory operand. As later stages of reload assume that all addresses found in the reg_equiv_* arrays were originally legitimate, - we ignore such REG_EQUIV notes. */ - if (memory_operand (x, VOIDmode)) + + It can also happen that a REG_EQUIV note contains a + readonly memory location. If the destination pseudo + is set from some other value (typically a different + pseudo), and the destination pseudo does not get a + hard reg, then reload will replace the destination + pseudo with its equivalent memory location. This + is horribly bad as it creates a store to a readonly + memory location and a runtime segfault. To avoid + this problem we reject readonly memory locations + for equivalences. This is overly conservative as + we could find all sets of the destination pseudo + and remove them as they should be redundant. */ + if (memory_operand (x, VOIDmode) && ! MEM_READONLY_P (x)) { /* Always unshare the equivalence, so we can substitute into this insn without touching the @@ -1071,8 +1073,7 @@ reload (rtx first, int global) reload_as_needed (global); - if (old_frame_size != get_frame_size ()) - abort (); + gcc_assert (old_frame_size == get_frame_size ()); if (num_eliminable) verify_initial_elim_offsets (); @@ -1089,8 +1090,8 @@ reload (rtx first, int global) CLEAR_REGNO_REG_SET (bb->global_live_at_start, HARD_FRAME_POINTER_REGNUM); - /* Come here (with failure set nonzero) if we can't get enough spill regs - and we decide not to abort about it. */ + /* Come here (with failure set nonzero) if we can't get enough spill + regs. */ failed: CLEAR_REG_SET (&spilled_pseudos); @@ -1129,8 +1130,7 @@ reload (rtx first, int global) MEM_COPY_ATTRIBUTES (reg, reg_equiv_memory_loc[i]); else { - RTX_UNCHANGING_P (reg) = MEM_IN_STRUCT_P (reg) - = MEM_SCALAR_P (reg) = 0; + MEM_IN_STRUCT_P (reg) = MEM_SCALAR_P (reg) = 0; MEM_ATTRS (reg) = 0; } } @@ -1186,6 +1186,19 @@ reload (rtx first, int global) replace_pseudos_in (& XEXP (PATTERN (insn), 0), VOIDmode, PATTERN (insn)); + /* Discard obvious no-ops, even without -O. This optimization + is fast and doesn't interfere with debugging. */ + if (NONJUMP_INSN_P (insn) + && GET_CODE (PATTERN (insn)) == SET + && REG_P (SET_SRC (PATTERN (insn))) + && REG_P (SET_DEST (PATTERN (insn))) + && (REGNO (SET_SRC (PATTERN (insn))) + == REGNO (SET_DEST (PATTERN (insn))))) + { + delete_insn (insn); + continue; + } + pnote = ®_NOTES (insn); while (*pnote != 0) { @@ -1220,10 +1233,10 @@ reload (rtx first, int global) if (size > STACK_CHECK_MAX_FRAME_SIZE) { - warning ("frame size too large for reliable stack checking"); + warning (0, "frame size too large for reliable stack checking"); if (! verbose_warned) { - warning ("try reducing the number of local variables"); + warning (0, "try reducing the number of local variables"); verbose_warned = 1; } } @@ -1577,8 +1590,7 @@ count_pseudo (int reg) SET_REGNO_REG_SET (&pseudos_counted, reg); - if (r < 0) - abort (); + gcc_assert (r >= 0); spill_add_cost[r] += freq; @@ -1593,9 +1605,10 @@ count_pseudo (int reg) static void order_regs_for_reload (struct insn_chain *chain) { - int i; + unsigned i; HARD_REG_SET used_by_pseudos; HARD_REG_SET used_by_pseudos2; + reg_set_iterator rsi; COPY_HARD_REG_SET (bad_spill_regs, fixed_reg_set); @@ -1616,15 +1629,15 @@ order_regs_for_reload (struct insn_chain *chain) CLEAR_REG_SET (&pseudos_counted); EXECUTE_IF_SET_IN_REG_SET - (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i, - { - count_pseudo (i); - }); + (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i, rsi) + { + count_pseudo (i); + } EXECUTE_IF_SET_IN_REG_SET - (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, - { - count_pseudo (i); - }); + (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, rsi) + { + count_pseudo (i); + } CLEAR_REG_SET (&pseudos_counted); } @@ -1670,6 +1683,7 @@ find_reg (struct insn_chain *chain, int order) int k; HARD_REG_SET not_usable; HARD_REG_SET used_by_other_reload; + reg_set_iterator rsi; COPY_HARD_REG_SET (not_usable, bad_spill_regs); IOR_HARD_REG_SET (not_usable, bad_spill_regs_global); @@ -1738,22 +1752,21 @@ find_reg (struct insn_chain *chain, int order) rl->regno = best_reg; EXECUTE_IF_SET_IN_REG_SET - (&chain->live_throughout, FIRST_PSEUDO_REGISTER, j, - { - count_spilled_pseudo (best_reg, rl->nregs, j); - }); + (&chain->live_throughout, FIRST_PSEUDO_REGISTER, j, rsi) + { + count_spilled_pseudo (best_reg, rl->nregs, j); + } EXECUTE_IF_SET_IN_REG_SET - (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, j, - { - count_spilled_pseudo (best_reg, rl->nregs, j); - }); + (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, j, rsi) + { + count_spilled_pseudo (best_reg, rl->nregs, j); + } for (i = 0; i < rl->nregs; i++) { - if (spill_cost[best_reg + i] != 0 - || spill_add_cost[best_reg + i] != 0) - abort (); + gcc_assert (spill_cost[best_reg + i] == 0); + gcc_assert (spill_add_cost[best_reg + i] == 0); SET_HARD_REG_BIT (used_spill_regs_local, best_reg + i); } return 1; @@ -1873,13 +1886,13 @@ delete_caller_save_insns (void) static void spill_failure (rtx insn, enum reg_class class) { - static const char *const reg_class_names[] = REG_CLASS_NAMES; if (asm_noperands (PATTERN (insn)) >= 0) - error_for_asm (insn, "can't find a register in class `%s' while reloading `asm'", + error_for_asm (insn, "can't find a register in class %qs while " + "reloading %", reg_class_names[class]); else { - error ("unable to find a register to spill in class `%s'", + error ("unable to find a register to spill in class %qs", reg_class_names[class]); fatal_insn ("this is the insn:", insn); } @@ -1965,8 +1978,6 @@ alter_reg (int i, int from_reg) below. */ adjust = inherent_size - total_size; - RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[i]); - /* Nothing can alias this slot except this pseudo. */ set_mem_alias_set (x, new_alias_set ()); } @@ -2037,7 +2048,7 @@ alter_reg (int i, int from_reg) /* If we have a decl for the original register, set it for the memory. If this is a shared MEM, make a copy. */ if (REG_EXPR (regno_reg_rtx[i]) - && TREE_CODE_CLASS (TREE_CODE (REG_EXPR (regno_reg_rtx[i]))) == 'd') + && DECL_P (REG_EXPR (regno_reg_rtx[i]))) { rtx decl = DECL_RTL_IF_SET (REG_EXPR (regno_reg_rtx[i])); @@ -2190,7 +2201,7 @@ set_label_offsets (rtx x, rtx insn, int initial_p) return; case LABEL_REF: - set_label_offsets (XEXP (SET_SRC (x), 0), insn, initial_p); + set_label_offsets (SET_SRC (x), insn, initial_p); return; case IF_THEN_ELSE: @@ -2558,7 +2569,7 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn) case CLOBBER: case ASM_OPERANDS: case SET: - abort (); + gcc_unreachable (); default: break; @@ -2870,13 +2881,12 @@ eliminate_regs_in_insn (rtx insn, int replace) if (! insn_is_asm && icode < 0) { - if (GET_CODE (PATTERN (insn)) == USE - || GET_CODE (PATTERN (insn)) == CLOBBER - || GET_CODE (PATTERN (insn)) == ADDR_VEC - || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC - || GET_CODE (PATTERN (insn)) == ASM_INPUT) - return 0; - abort (); + gcc_assert (GET_CODE (PATTERN (insn)) == USE + || GET_CODE (PATTERN (insn)) == CLOBBER + || GET_CODE (PATTERN (insn)) == ADDR_VEC + || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC + || GET_CODE (PATTERN (insn)) == ASM_INPUT); + return 0; } if (old_set != 0 && REG_P (SET_DEST (old_set)) @@ -3030,8 +3040,7 @@ eliminate_regs_in_insn (rtx insn, int replace) PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode, vec); add_clobbers (PATTERN (insn), INSN_CODE (insn)); } - if (INSN_CODE (insn) < 0) - abort (); + gcc_assert (INSN_CODE (insn) >= 0); } /* If we have a nonzero offset, and the source is already a simple REG, the following transformation would @@ -3302,13 +3311,11 @@ verify_initial_elim_offsets (void) for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) { INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, t); - if (t != ep->initial_offset) - abort (); + gcc_assert (t == ep->initial_offset); } #else INITIAL_FRAME_POINTER_OFFSET (t); - if (t != reg_eliminate[0].initial_offset) - abort (); + gcc_assert (t == reg_eliminate[0].initial_offset); #endif } @@ -3333,6 +3340,14 @@ set_initial_elim_offsets (void) num_not_at_initial_offset = 0; } +/* Subroutine of set_initial_label_offsets called via for_each_eh_label. */ + +static void +set_initial_eh_label_offset (rtx label) +{ + set_label_offsets (label, NULL_RTX, 1); +} + /* Initialize the known label offsets. Set a known offset for each forced label to be at the initial offset of each elimination. We do this because we assume that all @@ -3349,6 +3364,8 @@ set_initial_label_offsets (void) for (x = forced_labels; x; x = XEXP (x, 1)) if (XEXP (x, 0)) set_label_offsets (XEXP (x, 0), NULL_RTX, 1); + + for_each_eh_label (set_initial_eh_label_offset); } /* Set all elimination offsets to the known values for the code label given @@ -3541,15 +3558,6 @@ spill_hard_reg (unsigned int regno, int cant_eliminate) SET_REGNO_REG_SET (&spilled_pseudos, i); } -/* I'm getting weird preprocessor errors if I use IOR_HARD_REG_SET - from within EXECUTE_IF_SET_IN_REG_SET. Hence this awkwardness. */ - -static void -ior_hard_reg_set (HARD_REG_SET *set1, HARD_REG_SET *set2) -{ - IOR_HARD_REG_SET (*set1, *set2); -} - /* After find_reload_regs has been run for all insn that need reloads, and/or spill_hard_regs was called, this function is used to actually spill pseudo registers and try to reallocate them. It also sets up the @@ -3560,7 +3568,8 @@ finish_spills (int global) { struct insn_chain *chain; int something_changed = 0; - int i; + unsigned i; + reg_set_iterator rsi; /* Build the spill_regs array for the function. */ /* If there are some registers still to eliminate and one of the spill regs @@ -3587,21 +3596,19 @@ finish_spills (int global) else spill_reg_order[i] = -1; - EXECUTE_IF_SET_IN_REG_SET - (&spilled_pseudos, FIRST_PSEUDO_REGISTER, i, - { - /* Record the current hard register the pseudo is allocated to in - pseudo_previous_regs so we avoid reallocating it to the same - hard reg in a later pass. */ - if (reg_renumber[i] < 0) - abort (); - - 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; - /* We will need to scan everything again. */ - something_changed = 1; - }); + EXECUTE_IF_SET_IN_REG_SET (&spilled_pseudos, FIRST_PSEUDO_REGISTER, i, rsi) + { + /* Record the current hard register the pseudo is allocated to 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; + /* We will need to scan everything again. */ + something_changed = 1; + } /* Retry global register allocation if possible. */ if (global) @@ -3613,17 +3620,17 @@ finish_spills (int global) for (chain = insns_need_reload; chain; chain = chain->next_need_reload) { EXECUTE_IF_SET_IN_REG_SET - (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i, - { - ior_hard_reg_set (pseudo_forbidden_regs + i, - &chain->used_spill_regs); - }); + (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i, rsi) + { + IOR_HARD_REG_SET (pseudo_forbidden_regs[i], + chain->used_spill_regs); + } EXECUTE_IF_SET_IN_REG_SET - (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, - { - ior_hard_reg_set (pseudo_forbidden_regs + i, - &chain->used_spill_regs); - }); + (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, rsi) + { + IOR_HARD_REG_SET (pseudo_forbidden_regs[i], + chain->used_spill_regs); + } } /* Retry allocating the spilled pseudos. For each reg, merge the @@ -3631,7 +3638,7 @@ finish_spills (int global) and call retry_global_alloc. We change spill_pseudos here to only contain pseudos that did not get a new hard register. */ - for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) + for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++) if (reg_old_renumber[i] != reg_renumber[i]) { HARD_REG_SET forbidden; @@ -3673,13 +3680,13 @@ finish_spills (int global) /* Make sure we only enlarge the set. */ GO_IF_HARD_REG_SUBSET (used_by_pseudos2, chain->used_spill_regs, ok); - abort (); + gcc_unreachable (); ok:; } } /* Let alter_reg modify the reg rtx's for the modified pseudos. */ - for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) + for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++) { int regno = reg_renumber[i]; if (reg_old_renumber[i] == regno) @@ -3878,7 +3885,8 @@ reload_as_needed (int live_known) || (extract_insn (p), ! constrain_operands (1)))) { error_for_asm (insn, - "`asm' operand requires impossible reload"); + "% operand requires " + "impossible reload"); delete_insn (p); } } @@ -4051,7 +4059,7 @@ forget_old_reloads_1 (rtx x, rtx ignored ATTRIBUTE_UNUSED, unsigned int nr; /* note_stores does give us subregs of hard regs, - subreg_regno_offset will abort if it is not a hard reg. */ + subreg_regno_offset requires a hard reg. */ while (GET_CODE (x) == SUBREG) { /* We ignore the subreg offset when calculating the regno, @@ -4268,7 +4276,7 @@ clear_reload_reg_in_use (unsigned int regno, int opnum, used_in_set = &reload_reg_used_in_insn; break; default: - abort (); + gcc_unreachable (); } /* We resolve conflicts with remaining reloads of the same type by excluding the intervals of reload registers by them from the @@ -4464,8 +4472,10 @@ reload_reg_free_p (unsigned int regno, int opnum, enum reload_type type) case RELOAD_FOR_OTHER_ADDRESS: return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno); + + default: + gcc_unreachable (); } - abort (); } /* Return 1 if the value in reload reg REGNO, as used by a reload @@ -4597,9 +4607,10 @@ reload_reg_reaches_end_p (unsigned int regno, int opnum, enum reload_type type) return 0; return 1; - } - abort (); + default: + gcc_unreachable (); + } } /* Return 1 if the reloads denoted by R1 and R2 cannot share a register. @@ -4607,7 +4618,7 @@ reload_reg_reaches_end_p (unsigned int regno, int opnum, enum reload_type type) This function uses the same algorithm as reload_reg_free_p above. */ -int +static int reloads_conflict (int r1, int r2) { enum reload_type r1_type = rld[r1].when_needed; @@ -4674,25 +4685,25 @@ reloads_conflict (int r1, int r2) return 1; default: - abort (); + gcc_unreachable (); } } /* Indexed by reload number, 1 if incoming value inherited from previous insns. */ -char reload_inherited[MAX_RELOADS]; +static char reload_inherited[MAX_RELOADS]; /* For an inherited reload, this is the insn the reload was inherited from, if we know it. Otherwise, this is 0. */ -rtx reload_inheritance_insn[MAX_RELOADS]; +static rtx reload_inheritance_insn[MAX_RELOADS]; /* If nonzero, this is a place to get the value of the reload, rather than using reload_in. */ -rtx reload_override_in[MAX_RELOADS]; +static rtx reload_override_in[MAX_RELOADS]; /* For each reload, the hard register number of the register used, or -1 if we did not need a register for this reload. */ -int reload_spill_index[MAX_RELOADS]; +static int reload_spill_index[MAX_RELOADS]; /* Subroutine of free_for_value_p, used to check a single register. START_REGNO is the starting regno of the full reload register @@ -4952,11 +4963,11 @@ free_for_value_p (int regno, enum machine_mode mode, int opnum, } /* Return nonzero if the rtx X is invariant over the current function. */ -/* ??? Actually, the places where we use this expect exactly what - * is tested here, and not everything that is function invariant. In - * particular, the frame pointer and arg pointer are special cased; - * pic_offset_table_rtx is not, and this will cause aborts when we - * go to spill these things to memory. */ +/* ??? Actually, the places where we use this expect exactly what is + tested here, and not everything that is function invariant. In + particular, the frame pointer and arg pointer are special cased; + pic_offset_table_rtx is not, and we must not spill these things to + memory. */ static int function_invariant_p (rtx x) @@ -4998,7 +5009,7 @@ failed_reload (rtx insn, int r) /* It's the user's fault; the operand's mode and constraint don't match. Disable this reload so we don't crash in final. */ error_for_asm (insn, - "`asm' operand constraint incompatible with operand size"); + "% operand constraint incompatible with operand size"); rld[r].in = 0; rld[r].out = 0; rld[r].reg_rtx = 0; @@ -5425,19 +5436,18 @@ choose_reload_regs (struct insn_chain *chain) need_mode = mode; else need_mode - = smallest_mode_for_size (GET_MODE_SIZE (mode) + byte, + = smallest_mode_for_size (GET_MODE_BITSIZE (mode) + + byte * BITS_PER_UNIT, GET_MODE_CLASS (mode)); - if ( -#ifdef CANNOT_CHANGE_MODE_CLASS - (!REG_CANNOT_CHANGE_MODE_P (i, GET_MODE (last_reg), - need_mode) - && -#endif - (GET_MODE_SIZE (GET_MODE (last_reg)) + 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) @@ -5594,17 +5604,25 @@ choose_reload_regs (struct insn_chain *chain) { if (REG_P (equiv)) regno = REGNO (equiv); - else if (GET_CODE (equiv) == SUBREG) + else { /* This must be a SUBREG of a hard register. Make a new REG since this might be used in an address and not all machines support SUBREGs there. */ + gcc_assert (GET_CODE (equiv) == SUBREG); regno = subreg_regno (equiv); equiv = gen_rtx_REG (rld[r].mode, regno); + /* If we choose EQUIV as the reload register, but the + loop below decides to cancel the inheritance, we'll + end up reloading EQUIV in rld[r].mode, not the mode + it had originally. That isn't safe when EQUIV isn't + available as a spill register since its value might + still be live at this point. */ + for (i = regno; i < regno + (int) rld[r].nregs; i++) + if (TEST_HARD_REG_BIT (reload_reg_unavailable, i)) + equiv = 0; } - else - abort (); } /* If we found a spill reg, reject it unless it is free @@ -5808,15 +5826,13 @@ choose_reload_regs (struct insn_chain *chain) /* Some sanity tests to verify that the reloads found in the first pass are identical to the ones we have now. */ - if (chain->n_reloads != n_reloads) - abort (); + gcc_assert (chain->n_reloads == n_reloads); for (i = 0; i < n_reloads; i++) { if (chain->rld[i].regno < 0 || chain->rld[i].reg_rtx != 0) continue; - if (chain->rld[i].when_needed != rld[i].when_needed) - abort (); + gcc_assert (chain->rld[i].when_needed == rld[i].when_needed); for (j = 0; j < n_spills; j++) if (spill_regs[j] == chain->rld[i].regno) if (! set_reload_reg (j, i)) @@ -5929,10 +5945,9 @@ choose_reload_regs (struct insn_chain *chain) SET_HARD_REG_BIT (reg_is_output_reload, i + nr); } - if (rld[r].when_needed != RELOAD_OTHER - && rld[r].when_needed != RELOAD_FOR_OUTPUT - && rld[r].when_needed != RELOAD_FOR_INSN) - abort (); + gcc_assert (rld[r].when_needed == RELOAD_OTHER + || rld[r].when_needed == RELOAD_FOR_OUTPUT + || rld[r].when_needed == RELOAD_FOR_INSN); } } } @@ -6072,17 +6087,18 @@ merge_assigned_reloads (rtx insn) || rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS) ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER); - /* Check to see if we accidentally converted two reloads - that use the same reload register with different inputs - to the same type. If so, the resulting code won't work, - so abort. */ + /* Check to see if we accidentally converted two + reloads that use the same reload register with + different inputs to the same type. If so, the + resulting code won't work. */ if (rld[j].reg_rtx) for (k = 0; k < j; k++) - if (rld[k].in != 0 && rld[k].reg_rtx != 0 - && rld[k].when_needed == rld[j].when_needed - && rtx_equal_p (rld[k].reg_rtx, rld[j].reg_rtx) - && ! rtx_equal_p (rld[k].in, rld[j].in)) - abort (); + gcc_assert (rld[k].in == 0 || rld[k].reg_rtx == 0 + || rld[k].when_needed != rld[j].when_needed + || !rtx_equal_p (rld[k].reg_rtx, + rld[j].reg_rtx) + || rtx_equal_p (rld[k].in, + rld[j].in)); } } } @@ -6296,7 +6312,7 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, where = &other_input_address_reload_insns; break; default: - abort (); + gcc_unreachable (); } push_to_sequence (*where); @@ -6307,8 +6323,7 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, /* We are not going to bother supporting the case where a incremented register can't be copied directly from OLDEQUIV since this seems highly unlikely. */ - if (rl->secondary_in_reload >= 0) - abort (); + gcc_assert (rl->secondary_in_reload < 0); if (reload_inherited[j]) oldequiv = reloadreg; @@ -6621,7 +6636,7 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl, if (asm_noperands (PATTERN (insn)) < 0) /* It's the compiler's fault. */ fatal_insn ("VOIDmode on an output", insn); - error_for_asm (insn, "output operand is constant in `asm'"); + error_for_asm (insn, "output operand is constant in %"); /* Prevent crash--use something we know is valid. */ mode = word_mode; old = gen_rtx_REG (mode, REGNO (reloadreg)); @@ -6722,7 +6737,8 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl, || !(set = single_set (insn)) || rtx_equal_p (old, SET_DEST (set)) || !reg_mentioned_p (old, SET_SRC (set)) - || !regno_clobbered_p (REGNO (old), insn, rl->mode, 0)) + || !((REGNO (old) < FIRST_PSEUDO_REGISTER) + && regno_clobbered_p (REGNO (old), insn, rl->mode, 0))) gen_reload (old, reloadreg, rl->opnum, rl->when_needed); } @@ -6838,6 +6854,10 @@ do_input_reload (struct insn_chain *chain, struct reload *rl, int j) actually no need to store the old value in it. */ if (optimize + /* Only attempt this for input reloads; for RELOAD_OTHER we miss + that there may be multiple uses of the previous output reload. + Restricting to RELOAD_FOR_INPUT is mostly paranoia. */ + && rl->when_needed == RELOAD_FOR_INPUT && (reload_inherited[j] || reload_override_in[j]) && rl->reg_rtx && REG_P (rl->reg_rtx) @@ -6924,8 +6944,7 @@ do_output_reload (struct insn_chain *chain, struct reload *rl, int j) return; /* If is a JUMP_INSN, we can't support output reloads yet. */ - if (JUMP_P (insn)) - abort (); + gcc_assert (!JUMP_P (insn)); emit_output_reload_insns (chain, rld + j, j); } @@ -7019,25 +7038,25 @@ emit_reload_insns (struct insn_chain *chain) reloads for the operand. The RELOAD_OTHER output reloads are output in descending order by reload number. */ - emit_insn_before_sameloc (other_input_address_reload_insns, insn); - emit_insn_before_sameloc (other_input_reload_insns, insn); + emit_insn_before (other_input_address_reload_insns, insn); + emit_insn_before (other_input_reload_insns, insn); for (j = 0; j < reload_n_operands; j++) { - emit_insn_before_sameloc (inpaddr_address_reload_insns[j], insn); - emit_insn_before_sameloc (input_address_reload_insns[j], insn); - emit_insn_before_sameloc (input_reload_insns[j], insn); + emit_insn_before (inpaddr_address_reload_insns[j], insn); + emit_insn_before (input_address_reload_insns[j], insn); + emit_insn_before (input_reload_insns[j], insn); } - emit_insn_before_sameloc (other_operand_reload_insns, insn); - emit_insn_before_sameloc (operand_reload_insns, insn); + emit_insn_before (other_operand_reload_insns, insn); + emit_insn_before (operand_reload_insns, insn); for (j = 0; j < reload_n_operands; j++) { - rtx x = emit_insn_after_sameloc (outaddr_address_reload_insns[j], insn); - x = emit_insn_after_sameloc (output_address_reload_insns[j], x); - x = emit_insn_after_sameloc (output_reload_insns[j], x); - emit_insn_after_sameloc (other_output_reload_insns[j], x); + rtx x = emit_insn_after (outaddr_address_reload_insns[j], insn); + x = emit_insn_after (output_address_reload_insns[j], x); + x = emit_insn_after (output_reload_insns[j], x); + emit_insn_after (other_output_reload_insns[j], x); } /* For all the spill regs newly reloaded in this instruction, @@ -7353,7 +7372,7 @@ emit_reload_insns (struct insn_chain *chain) Returns first insn emitted. */ -rtx +static rtx gen_reload (rtx out, rtx in, int opnum, enum reload_type type) { rtx last = get_last_insn (); @@ -7637,13 +7656,13 @@ delete_output_reload (rtx insn, int j, int last_reload_reg) /* If the pseudo-reg we are reloading is no longer referenced anywhere between the store into it and here, - and no jumps or labels intervene, then the value can get - here through the reload reg alone. + and we're within the same basic block, then the value can only + pass through the reload reg and end up here. Otherwise, give up--return. */ for (i1 = NEXT_INSN (output_reload_insn); i1 != insn; i1 = NEXT_INSN (i1)) { - if (LABEL_P (i1) || JUMP_P (i1)) + if (NOTE_INSN_BASIC_BLOCK_P (i1)) return; if ((NONJUMP_INSN_P (i1) || CALL_P (i1)) && reg_mentioned_p (reg, PATTERN (i1))) @@ -8044,10 +8063,11 @@ fixup_abnormal_edges (void) FOR_EACH_BB (bb) { edge e; + edge_iterator ei; /* Look for cases we are interested in - calls or instructions causing exceptions. */ - for (e = bb->succ; e; e = e->succ_next) + FOR_EACH_EDGE (e, ei, bb->succs) { if (e->flags & EDGE_ABNORMAL_CALL) break; @@ -8060,7 +8080,7 @@ fixup_abnormal_edges (void) { rtx insn = BB_END (bb), stop = NEXT_INSN (BB_END (bb)); rtx next; - for (e = bb->succ; e; e = e->succ_next) + FOR_EACH_EDGE (e, ei, bb->succs) if (e->flags & EDGE_FALLTHRU) break; /* Get past the new insns generated. Allow notes, as the insns may @@ -8069,8 +8089,7 @@ fixup_abnormal_edges (void) && !can_throw_internal (insn) && insn != BB_HEAD (bb)) insn = PREV_INSN (insn); - if (!CALL_P (insn) && !can_throw_internal (insn)) - abort (); + gcc_assert (CALL_P (insn) || can_throw_internal (insn)); BB_END (bb) = insn; inserted = true; insn = NEXT_INSN (insn);