X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Freload1.c;h=ed6a07d000bf279d908cbbdedf5212efab2e5edb;hp=a45e904205a427bb079805e85e625039e5d4429e;hb=9238bd6d3140e42e78f067948d12c288054a5cd3;hpb=04b0809705f6256be2fb97ea7f0ed49b92545016 diff --git a/gcc/reload1.c b/gcc/reload1.c index a45e904205a..ed6a07d000b 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -1,5 +1,5 @@ /* Reload pseudo regs into hard regs for insns that require hard regs. - Copyright (C) 1987, 88, 89, 92-5, 1996 Free Software Foundation, Inc. + Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc. This file is part of GNU CC. @@ -253,6 +253,18 @@ int reload_first_uid; int caller_save_needed; +/* The register class to use for a base register when reloading an + address. This is normally BASE_REG_CLASS, but it may be different + when using SMALL_REGISTER_CLASSES and passing parameters in + registers. */ +enum reg_class reload_address_base_reg_class; + +/* The register class to use for an index register when reloading an + address. This is normally INDEX_REG_CLASS, but it may be different + when using SMALL_REGISTER_CLASSES and passing parameters in + registers. */ +enum reg_class reload_address_index_reg_class; + /* Set to 1 while reload_as_needed is operating. Required by some machines to handle any generated moves differently. */ @@ -381,6 +393,17 @@ static void delete_output_reload PROTO((rtx, int, rtx)); static void inc_for_reload PROTO((rtx, rtx, int)); static int constraint_accepts_reg_p PROTO((char *, rtx)); static int count_occurrences PROTO((rtx, rtx)); +static void reload_cse_invalidate_regno PROTO((int, enum machine_mode, int)); +static int reload_cse_mem_conflict_p PROTO((rtx, rtx, enum machine_mode, + rtx)); +static void reload_cse_invalidate_mem PROTO((rtx)); +static void reload_cse_invalidate_rtx PROTO((rtx, rtx)); +static void reload_cse_regs PROTO((rtx)); +static int reload_cse_regno_equal_p PROTO((int, rtx, enum machine_mode)); +static int reload_cse_noop_set_p PROTO((rtx, rtx)); +static void reload_cse_simplify_set PROTO((rtx, rtx)); +static void reload_cse_check_clobber PROTO((rtx, rtx)); +static void reload_cse_record_set PROTO((rtx, rtx)); /* Initialize the reload pass once per compilation. */ @@ -431,6 +454,66 @@ init_reload () /* Initialize obstack for our rtl allocation. */ gcc_obstack_init (&reload_obstack); reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0); + + /* Decide which register class should be used when reloading + addresses. If we are using SMALL_REGISTER_CLASSES, and any + parameters are passed in registers, then we do not want to use + those registers when reloading an address. Otherwise, if a + function argument needs a reload, we may wind up clobbering + another argument to the function which was already computed. If + we find a subset class which simply avoids those registers, we + use it instead. ??? It would be better to only use the + restricted class when we actually are loading function arguments, + but that is hard to determine. */ + reload_address_base_reg_class = BASE_REG_CLASS; + reload_address_index_reg_class = INDEX_REG_CLASS; +#ifdef SMALL_REGISTER_CLASSES + if (SMALL_REGISTER_CLASSES) + { + int regno; + HARD_REG_SET base, index; + enum reg_class *p; + + COPY_HARD_REG_SET (base, reg_class_contents[BASE_REG_CLASS]); + COPY_HARD_REG_SET (index, reg_class_contents[INDEX_REG_CLASS]); + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + { + if (FUNCTION_ARG_REGNO_P (regno)) + { + CLEAR_HARD_REG_BIT (base, regno); + CLEAR_HARD_REG_BIT (index, regno); + } + } + + GO_IF_HARD_REG_EQUAL (base, reg_class_contents[BASE_REG_CLASS], + baseok); + for (p = reg_class_subclasses[BASE_REG_CLASS]; + *p != LIM_REG_CLASSES; + p++) + { + GO_IF_HARD_REG_EQUAL (base, reg_class_contents[*p], usebase); + continue; + usebase: + reload_address_base_reg_class = *p; + break; + } + baseok:; + + GO_IF_HARD_REG_EQUAL (index, reg_class_contents[INDEX_REG_CLASS], + indexok); + for (p = reg_class_subclasses[INDEX_REG_CLASS]; + *p != LIM_REG_CLASSES; + p++) + { + GO_IF_HARD_REG_EQUAL (index, reg_class_contents[*p], useindex); + continue; + useindex: + reload_address_index_reg_class = *p; + break; + } + indexok:; + } +#endif /* SMALL_REGISTER_CLASSES */ } /* Main entry point for the reload pass. @@ -462,6 +545,11 @@ reload (first, global, dumpfile) register rtx insn; register struct elim_table *ep; + /* The two pointers used to track the true location of the memory used + for label offsets. */ + char *real_known_ptr = NULL_PTR; + int (*real_at_ptr)[NUM_ELIMINABLE_REGS]; + int something_changed; int something_needs_reloads; int something_needs_elimination; @@ -506,10 +594,18 @@ reload (first, global, dumpfile) as homes for pseudo registers. This is done here rather than (eg) in global_alloc because this point is reached even if not optimizing. */ - for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) mark_home_live (i); + /* A function that receives a nonlocal goto must save all call-saved + registers. */ + if (current_function_has_nonlocal_label) + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + if (! call_used_regs[i] && ! fixed_regs[i]) + regs_ever_live[i] = 1; + } + for (i = 0; i < scratch_list_length; i++) if (scratch_list[i]) mark_scratch_live (scratch_list[i]); @@ -544,7 +640,8 @@ reload (first, global, dumpfile) bzero (cannot_omit_stores, max_regno); #ifdef SMALL_REGISTER_CLASSES - CLEAR_HARD_REG_SET (forbidden_regs); + if (SMALL_REGISTER_CLASSES) + CLEAR_HARD_REG_SET (forbidden_regs); #endif /* Look for REG_EQUIV notes; record what each pseudo is equivalent to. @@ -659,13 +756,17 @@ reload (first, global, dumpfile) num_labels = max_label_num () - get_first_label_num (); /* Allocate the tables used to store offset information at labels. */ - offsets_known_at = (char *) alloca (num_labels); - offsets_at + /* We used to use alloca here, but the size of what it would try to + allocate would occasionally cause it to exceed the stack limit and + cause a core dump. */ + real_known_ptr = xmalloc (num_labels); + real_at_ptr = (int (*)[NUM_ELIMINABLE_REGS]) - alloca (num_labels * NUM_ELIMINABLE_REGS * sizeof (int)); + xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (int)); - offsets_known_at -= get_first_label_num (); - offsets_at -= get_first_label_num (); + offsets_known_at = real_known_ptr - get_first_label_num (); + offsets_at + = (int (*)[NUM_ELIMINABLE_REGS]) (real_at_ptr - get_first_label_num ()); /* Alter each pseudo-reg rtx to contain its hard reg number. Assign stack slots to the pseudos that lack hard regs or equivalents. @@ -674,11 +775,6 @@ reload (first, global, dumpfile) for (i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++) alter_reg (i, -1); - /* Round size of stack frame to BIGGEST_ALIGNMENT. This must be done here - because the stack size may be a part of the offset computation for - register elimination. */ - assign_stack_local (BLKmode, 0, 0); - /* If we have some registers we think can be eliminated, scan all insns to see if there is an insn that sets one of these registers to something other than itself plus a constant. If so, the register cannot be @@ -698,11 +794,15 @@ reload (first, global, dumpfile) in that case some pseudos might be in the wrong kind of hard reg. */ for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) - if (reg_renumber[i] == -1 && reg_n_refs[i] != 0) + if (reg_renumber[i] == -1 && REG_N_REFS (i) != 0) break; if (i == max_regno && num_eliminable == 0 && ! caller_save_needed) - return; + { + free (real_known_ptr); + free (real_at_ptr); + return; + } #endif /* Compute the order of preference for hard registers to spill. @@ -722,9 +822,10 @@ reload (first, global, dumpfile) rtl as a spill register. But on some, we have to. Those will have taken care to keep the life of hard regs as short as possible. */ -#ifndef SMALL_REGISTER_CLASSES - COPY_HARD_REG_SET (forbidden_regs, bad_spill_regs); +#ifdef SMALL_REGISTER_CLASSES + if (! SMALL_REGISTER_CLASSES) #endif + COPY_HARD_REG_SET (forbidden_regs, bad_spill_regs); /* Spill any hard regs that we know we can't eliminate. */ for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) @@ -787,7 +888,7 @@ reload (first, global, dumpfile) rtx max_groups_insn[N_REG_CLASSES]; rtx max_nongroups_insn[N_REG_CLASSES]; rtx x; - int starting_frame_size = get_frame_size (); + HOST_WIDE_INT starting_frame_size; int previous_frame_pointer_needed = frame_pointer_needed; static char *reg_class_names[] = REG_CLASS_NAMES; @@ -809,6 +910,14 @@ reload (first, global, dumpfile) changes from 0 to 1 in this pass. */ new_basic_block_needs = 0; + /* Round size of stack frame to BIGGEST_ALIGNMENT. 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. */ + assign_stack_local (BLKmode, 0, 0); + + starting_frame_size = get_frame_size (); + /* Reset all offsets on eliminable registers to their initial values. */ #ifdef ELIMINABLE_REGS for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) @@ -869,7 +978,7 @@ reload (first, global, dumpfile) for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) if (reg_renumber[i] < 0 && reg_equiv_memory_loc[i]) { - rtx x = eliminate_regs (reg_equiv_memory_loc[i], 0, NULL_RTX); + rtx x = eliminate_regs (reg_equiv_memory_loc[i], 0, NULL_RTX, 0); if (strict_memory_address_p (GET_MODE (regno_reg_rtx[i]), XEXP (x, 0))) @@ -976,7 +1085,9 @@ reload (first, global, dumpfile) struct needs op_addr; struct needs op_addr_reload; struct needs in_addr[MAX_RECOG_OPERANDS]; + struct needs in_addr_addr[MAX_RECOG_OPERANDS]; struct needs out_addr[MAX_RECOG_OPERANDS]; + struct needs out_addr_addr[MAX_RECOG_OPERANDS]; } insn_needs; /* If needed, eliminate any eliminable registers. */ @@ -986,7 +1097,7 @@ reload (first, global, dumpfile) #ifdef SMALL_REGISTER_CLASSES /* Set avoid_return_reg if this is an insn that might use the value of a function call. */ - if (GET_CODE (insn) == CALL_INSN) + if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN) { if (GET_CODE (PATTERN (insn)) == SET) after_call = SET_DEST (PATTERN (insn)); @@ -996,7 +1107,8 @@ reload (first, global, dumpfile) else after_call = 0; } - else if (after_call != 0 + else if (SMALL_REGISTER_CLASSES + && after_call != 0 && !(GET_CODE (PATTERN (insn)) == SET && SET_DEST (PATTERN (insn)) == stack_pointer_rtx)) { @@ -1135,9 +1247,15 @@ reload (first, global, dumpfile) case RELOAD_FOR_INPUT_ADDRESS: this_needs = &insn_needs.in_addr[reload_opnum[i]]; break; + case RELOAD_FOR_INPADDR_ADDRESS: + this_needs = &insn_needs.in_addr_addr[reload_opnum[i]]; + break; case RELOAD_FOR_OUTPUT_ADDRESS: this_needs = &insn_needs.out_addr[reload_opnum[i]]; break; + case RELOAD_FOR_OUTADDR_ADDRESS: + this_needs = &insn_needs.out_addr_addr[reload_opnum[i]]; + break; case RELOAD_FOR_OPERAND_ADDRESS: this_needs = &insn_needs.op_addr; break; @@ -1211,8 +1329,14 @@ reload (first, global, dumpfile) { in_max = MAX (in_max, insn_needs.in_addr[k].regs[j][i]); + in_max + = MAX (in_max, + insn_needs.in_addr_addr[k].regs[j][i]); out_max = MAX (out_max, insn_needs.out_addr[k].regs[j][i]); + out_max + = MAX (out_max, + insn_needs.out_addr_addr[k].regs[j][i]); } /* RELOAD_FOR_INSN reloads conflict with inputs, outputs, @@ -1246,8 +1370,12 @@ reload (first, global, dumpfile) j < reload_n_operands; j++) { in_max = MAX (in_max, insn_needs.in_addr[j].groups[i]); + in_max = MAX (in_max, + insn_needs.in_addr_addr[j].groups[i]); out_max = MAX (out_max, insn_needs.out_addr[j].groups[i]); + out_max + = MAX (out_max, insn_needs.out_addr_addr[j].groups[i]); } in_max = MAX (MAX (insn_needs.op_addr.groups[i], @@ -1344,7 +1472,7 @@ reload (first, global, dumpfile) This makes sure we have a register available that does not overlap the return value. */ - if (avoid_return_reg) + if (SMALL_REGISTER_CLASSES && avoid_return_reg) { int regno = REGNO (avoid_return_reg); int nregs @@ -1702,7 +1830,7 @@ reload (first, global, dumpfile) /* We can't complete a group, so start one. */ #ifdef SMALL_REGISTER_CLASSES /* Look for a pair neither of which is explicitly used. */ - if (i == FIRST_PSEUDO_REGISTER) + if (SMALL_REGISTER_CLASSES && i == FIRST_PSEUDO_REGISTER) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { int k; @@ -2010,6 +2138,10 @@ reload (first, global, dumpfile) } } + /* Do a very simple CSE pass over just the hard registers. */ + if (optimize > 0) + reload_cse_regs (first); + #ifdef PRESERVE_DEATH_INFO_REGNO_P /* Make a pass over all the insns and remove death notes for things that are no longer registers or no longer die in the insn (e.g., an input @@ -2035,6 +2167,11 @@ reload (first, global, dumpfile) reg_equiv_constant = 0; reg_equiv_memory_loc = 0; + if (real_known_ptr) + free (real_known_ptr); + if (real_at_ptr) + free (real_at_ptr); + if (scratch_list) free (scratch_list); scratch_list = 0; @@ -2352,7 +2489,7 @@ alter_reg (i, from_reg) allocate a stack slot for it. */ if (reg_renumber[i] < 0 - && reg_n_refs[i] > 0 + && REG_N_REFS (i) > 0 && reg_equiv_constant[i] == 0 && reg_equiv_memory_loc[i] == 0) { @@ -2372,7 +2509,8 @@ alter_reg (i, 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, -1); + x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size, + inherent_size == total_size ? 0 : -1); if (BYTES_BIG_ENDIAN) /* Cancel the big-endian correction done in assign_stack_local. Get the address of the beginning of the slot. @@ -2404,7 +2542,8 @@ alter_reg (i, from_reg) total_size = spill_stack_slot_width[from_reg]; } /* Make a slot with that size. */ - x = assign_stack_local (mode, total_size, -1); + x = assign_stack_local (mode, total_size, + inherent_size == total_size ? 0 : -1); stack_slot = x; if (BYTES_BIG_ENDIAN) { @@ -2661,10 +2800,11 @@ static struct rtvec_def *old_asm_operands_vec, *new_asm_operands_vec; the proper thing. */ rtx -eliminate_regs (x, mem_mode, insn) +eliminate_regs (x, mem_mode, insn, storing) rtx x; enum machine_mode mem_mode; rtx insn; + int storing; { enum rtx_code code = GET_CODE (x); struct elim_table *ep; @@ -2721,7 +2861,7 @@ eliminate_regs (x, mem_mode, insn) reference to the pseudo. Ensure we make a copy of the address in case it is shared. */ new = eliminate_regs (reg_equiv_memory_loc[regno], - mem_mode, insn); + mem_mode, insn, 0); if (new != reg_equiv_memory_loc[regno]) { cannot_omit_stores[regno] = 1; @@ -2783,8 +2923,8 @@ eliminate_regs (x, mem_mode, insn) reload. This is the desired action. */ { - rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn); - rtx new1 = eliminate_regs (XEXP (x, 1), mem_mode, insn); + rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0); + rtx new1 = eliminate_regs (XEXP (x, 1), mem_mode, insn, 0); if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1)) { @@ -2855,9 +2995,9 @@ eliminate_regs (x, mem_mode, insn) case GE: case GT: case GEU: case GTU: case LE: case LT: case LEU: case LTU: { - rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn); + rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0); rtx new1 - = XEXP (x, 1) ? eliminate_regs (XEXP (x, 1), mem_mode, insn) : 0; + = XEXP (x, 1) ? eliminate_regs (XEXP (x, 1), mem_mode, insn, 0) : 0; if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1)) return gen_rtx (code, GET_MODE (x), new0, new1); @@ -2868,7 +3008,7 @@ eliminate_regs (x, mem_mode, insn) /* If we have something in XEXP (x, 0), the usual case, eliminate it. */ if (XEXP (x, 0)) { - new = eliminate_regs (XEXP (x, 0), mem_mode, insn); + new = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0); if (new != XEXP (x, 0)) x = gen_rtx (EXPR_LIST, REG_NOTE_KIND (x), new, XEXP (x, 1)); } @@ -2881,7 +3021,7 @@ eliminate_regs (x, mem_mode, insn) strictly needed, but it simplifies the code. */ if (XEXP (x, 1)) { - new = eliminate_regs (XEXP (x, 1), mem_mode, insn); + new = eliminate_regs (XEXP (x, 1), mem_mode, insn, 0); if (new != XEXP (x, 1)) return gen_rtx (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new); } @@ -2917,7 +3057,7 @@ eliminate_regs (x, mem_mode, insn) case ABS: case SQRT: case FFS: - new = eliminate_regs (XEXP (x, 0), mem_mode, insn); + new = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0); if (new != XEXP (x, 0)) return gen_rtx (code, GET_MODE (x), new); return x; @@ -2936,7 +3076,7 @@ eliminate_regs (x, mem_mode, insn) && reg_equiv_memory_loc[REGNO (SUBREG_REG (x))] != 0) { new = eliminate_regs (reg_equiv_memory_loc[REGNO (SUBREG_REG (x))], - mem_mode, insn); + mem_mode, insn, 0); /* If we didn't change anything, we must retain the pseudo. */ if (new == reg_equiv_memory_loc[REGNO (SUBREG_REG (x))]) @@ -2956,27 +3096,37 @@ eliminate_regs (x, mem_mode, insn) } } else - new = eliminate_regs (SUBREG_REG (x), mem_mode, insn); + new = eliminate_regs (SUBREG_REG (x), mem_mode, insn, 0); if (new != XEXP (x, 0)) { - if (GET_CODE (new) == MEM - && (GET_MODE_SIZE (GET_MODE (x)) - <= GET_MODE_SIZE (GET_MODE (new))) + int x_size = GET_MODE_SIZE (GET_MODE (x)); + int new_size = GET_MODE_SIZE (GET_MODE (new)); + + /* When asked to spill a partial word subreg, we need to go + ahead and spill the whole thing against the possibility + that we reload the whole reg and find garbage at the top. */ + if (storing + && GET_CODE (new) == MEM + && x_size < new_size + && ((x_size + UNITS_PER_WORD-1) / UNITS_PER_WORD + == (new_size + UNITS_PER_WORD-1) / UNITS_PER_WORD)) + return new; + else if (GET_CODE (new) == MEM + && x_size <= new_size #ifdef LOAD_EXTEND_OP - /* On these machines we will be reloading what is - inside the SUBREG if it originally was a pseudo and - the inner and outer modes are both a word or - smaller. So leave the SUBREG then. */ - && ! (GET_CODE (SUBREG_REG (x)) == REG - && GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD - && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD - && (GET_MODE_SIZE (GET_MODE (x)) - > GET_MODE_SIZE (GET_MODE (new))) - && INTEGRAL_MODE_P (GET_MODE (new)) - && LOAD_EXTEND_OP (GET_MODE (new)) != NIL) + /* On these machines we will be reloading what is + inside the SUBREG if it originally was a pseudo and + the inner and outer modes are both a word or + smaller. So leave the SUBREG then. */ + && ! (GET_CODE (SUBREG_REG (x)) == REG + && x_size <= UNITS_PER_WORD + && new_size <= UNITS_PER_WORD + && x_size > new_size + && INTEGRAL_MODE_P (GET_MODE (new)) + && LOAD_EXTEND_OP (GET_MODE (new)) != NIL) #endif - ) + ) { int offset = SUBREG_WORD (x) * UNITS_PER_WORD; enum machine_mode mode = GET_MODE (x); @@ -3004,7 +3154,7 @@ eliminate_regs (x, mem_mode, insn) if (ep->from_rtx == XEXP (x, 0)) ep->can_eliminate = 0; - new = eliminate_regs (XEXP (x, 0), mem_mode, insn); + new = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0); if (new != XEXP (x, 0)) return gen_rtx (code, GET_MODE (x), new); return x; @@ -3017,7 +3167,7 @@ eliminate_regs (x, mem_mode, insn) if (ep->to_rtx == XEXP (x, 0)) ep->can_eliminate = 0; - new = eliminate_regs (XEXP (x, 0), mem_mode, insn); + new = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0); if (new != XEXP (x, 0)) return gen_rtx (code, GET_MODE (x), new); return x; @@ -3035,7 +3185,7 @@ eliminate_regs (x, mem_mode, insn) temp_vec = (rtx *) alloca (XVECLEN (x, 3) * sizeof (rtx)); for (i = 0; i < ASM_OPERANDS_INPUT_LENGTH (x); i++) temp_vec[i] = eliminate_regs (ASM_OPERANDS_INPUT (x, i), - mem_mode, insn); + mem_mode, insn, 0); for (i = 0; i < ASM_OPERANDS_INPUT_LENGTH (x); i++) if (temp_vec[i] != ASM_OPERANDS_INPUT (x, i)) @@ -3106,8 +3256,8 @@ eliminate_regs (x, mem_mode, insn) /* Now avoid the loop below in this common case. */ { - rtx new0 = eliminate_regs (SET_DEST (x), 0, insn); - rtx new1 = eliminate_regs (SET_SRC (x), 0, insn); + rtx new0 = eliminate_regs (SET_DEST (x), 0, insn, 1); + rtx new1 = eliminate_regs (SET_SRC (x), 0, insn, 0); /* If SET_DEST changed from a REG to a MEM and INSN is an insn, write a CLOBBER insn. */ @@ -3126,7 +3276,7 @@ eliminate_regs (x, mem_mode, insn) /* Our only special processing is to pass the mode of the MEM to our recursive call and copy the flags. While we are here, handle this case more efficiently. */ - new = eliminate_regs (XEXP (x, 0), GET_MODE (x), insn); + new = eliminate_regs (XEXP (x, 0), GET_MODE (x), insn, 0); if (new != XEXP (x, 0)) { new = gen_rtx (MEM, GET_MODE (x), new); @@ -3146,7 +3296,7 @@ eliminate_regs (x, mem_mode, insn) { if (*fmt == 'e') { - new = eliminate_regs (XEXP (x, i), mem_mode, insn); + new = eliminate_regs (XEXP (x, i), mem_mode, insn, 0); if (new != XEXP (x, i) && ! copied) { rtx new_x = rtx_alloc (code); @@ -3163,11 +3313,11 @@ eliminate_regs (x, mem_mode, insn) int copied_vec = 0; for (j = 0; j < XVECLEN (x, i); j++) { - new = eliminate_regs (XVECEXP (x, i, j), mem_mode, insn); + new = eliminate_regs (XVECEXP (x, i, j), mem_mode, insn, 0); if (new != XVECEXP (x, i, j) && ! copied_vec) { - rtvec new_v = gen_rtvec_v (XVECLEN (x, i), - &XVECEXP (x, i, 0)); + rtvec new_v = gen_rtvec_vv (XVECLEN (x, i), + XVEC (x, i)->elem); if (! copied) { rtx new_x = rtx_alloc (code); @@ -3234,12 +3384,29 @@ eliminate_regs_in_insn (insn, replace) { rtx src = SET_SRC (old_set); int offset, ok = 0; + rtx prev_insn, prev_set; if (src == ep->to_rtx) offset = 0, ok = 1; else if (GET_CODE (src) == PLUS && GET_CODE (XEXP (src, 0)) == CONST_INT) offset = INTVAL (XEXP (src, 0)), ok = 1; + else if ((prev_insn = prev_nonnote_insn (insn)) != 0 + && (prev_set = single_set (prev_insn)) != 0 + && rtx_equal_p (SET_DEST (prev_set), src)) + { + src = SET_SRC (prev_set); + if (src == ep->to_rtx) + offset = 0, ok = 1; + else if (GET_CODE (src) == PLUS + && GET_CODE (XEXP (src, 0)) == CONST_INT + && XEXP (src, 1) == ep->to_rtx) + offset = INTVAL (XEXP (src, 0)), ok = 1; + else if (GET_CODE (src) == PLUS + && GET_CODE (XEXP (src, 1)) == CONST_INT + && XEXP (src, 0) == ep->to_rtx) + offset = INTVAL (XEXP (src, 1)), ok = 1; + } if (ok) { @@ -3324,7 +3491,7 @@ eliminate_regs_in_insn (insn, replace) but now can do this as a load-address. This saves an insn in this common case. */ - new_body = eliminate_regs (old_body, 0, replace ? insn : NULL_RTX); + new_body = eliminate_regs (old_body, 0, replace ? insn : NULL_RTX, 0); if (new_body != old_body) { /* If we aren't replacing things permanently and we changed something, @@ -3413,7 +3580,7 @@ eliminate_regs_in_insn (insn, replace) of spill registers to be needed in the final reload pass than in the pre-passes. */ if (val && REG_NOTES (insn) != 0) - REG_NOTES (insn) = eliminate_regs (REG_NOTES (insn), 0, REG_NOTES (insn)); + REG_NOTES (insn) = eliminate_regs (REG_NOTES (insn), 0, REG_NOTES (insn), 0); if (! replace) pop_obstacks (); @@ -3510,14 +3677,14 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate) if (! cant_eliminate && basic_block_needs[0] - && reg_basic_block[i] >= 0 - && basic_block_needs[(int) class][reg_basic_block[i]] == 0) + && REG_BASIC_BLOCK (i) >= 0 + && basic_block_needs[(int) class][REG_BASIC_BLOCK (i)] == 0) { enum reg_class *p; for (p = reg_class_superclasses[(int) class]; *p != LIM_REG_CLASSES; p++) - if (basic_block_needs[(int) *p][reg_basic_block[i]] > 0) + if (basic_block_needs[(int) *p][REG_BASIC_BLOCK (i)] > 0) break; if (*p == LIM_REG_CLASSES) @@ -3584,7 +3751,9 @@ scan_paradoxical_subregs (x) { case REG: #ifdef SMALL_REGISTER_CLASSES - if (REGNO (x) < FIRST_PSEUDO_REGISTER && REG_USERVAR_P (x)) + if (SMALL_REGISTER_CLASSES + && REGNO (x) < FIRST_PSEUDO_REGISTER + && REG_USERVAR_P (x)) SET_HARD_REG_BIT (forbidden_regs, REGNO (x)); #endif return; @@ -3676,12 +3845,12 @@ order_regs_for_reload (global) we're not going to be able to reallocate it, but we might if allocated by global alloc. */ if (global && reg_allocno[i] < 0) - hard_reg_n_uses[regno].uses += (reg_n_refs[i] + 1) / 2; + hard_reg_n_uses[regno].uses += (REG_N_REFS (i) + 1) / 2; - hard_reg_n_uses[regno++].uses += reg_n_refs[i]; + hard_reg_n_uses[regno++].uses += REG_N_REFS (i); } } - large += reg_n_refs[i]; + large += REG_N_REFS (i); } /* Now fixed registers (which cannot safely be used for reloading) @@ -3698,14 +3867,15 @@ order_regs_for_reload (global) else if (regs_explicitly_used[i]) { hard_reg_n_uses[i].uses += large + 1; -#ifndef SMALL_REGISTER_CLASSES /* ??? We are doing this here because of the potential that bad code may be generated if a register explicitly used in an insn was used as a spill register for that insn. But not using these are spill registers may lose on some machine. We'll have to see how this works out. */ - SET_HARD_REG_BIT (bad_spill_regs, i); +#ifdef SMALL_REGISTER_CLASSES + if (! SMALL_REGISTER_CLASSES) #endif + SET_HARD_REG_BIT (bad_spill_regs, i); } } hard_reg_n_uses[HARD_FRAME_POINTER_REGNUM].uses += 2 * large + 2; @@ -3859,7 +4029,7 @@ reload_as_needed (first, live_known) #ifdef SMALL_REGISTER_CLASSES /* Set avoid_return_reg if this is an insn that might use the value of a function call. */ - if (GET_CODE (insn) == CALL_INSN) + if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN) { if (GET_CODE (PATTERN (insn)) == SET) after_call = SET_DEST (PATTERN (insn)); @@ -3869,7 +4039,8 @@ reload_as_needed (first, live_known) else after_call = 0; } - else if (after_call != 0 + else if (SMALL_REGISTER_CLASSES + && after_call != 0 && !(GET_CODE (PATTERN (insn)) == SET && SET_DEST (PATTERN (insn)) == stack_pointer_rtx)) { @@ -3887,7 +4058,8 @@ reload_as_needed (first, live_known) && GET_CODE (XEXP (PATTERN (insn), 0)) == MEM) XEXP (XEXP (PATTERN (insn), 0), 0) = eliminate_regs (XEXP (XEXP (PATTERN (insn), 0), 0), - GET_MODE (XEXP (PATTERN (insn), 0)), NULL_RTX); + GET_MODE (XEXP (PATTERN (insn), 0)), + NULL_RTX, 0); /* If we need to do register elimination processing, do so. This might delete the insn, in which case we are done. */ @@ -3947,7 +4119,8 @@ reload_as_needed (first, 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. */ - merge_assigned_reloads (insn); + if (SMALL_REGISTER_CLASSES) + merge_assigned_reloads (insn); #endif /* Generate the insns to reload operands into or out of @@ -4159,8 +4332,12 @@ reload_reg_class_lower (r1p, r2p) static HARD_REG_SET reload_reg_used; /* If reg is in use for a RELOAD_FOR_INPUT_ADDRESS reload for operand I. */ static HARD_REG_SET reload_reg_used_in_input_addr[MAX_RECOG_OPERANDS]; +/* If reg is in use for a RELOAD_FOR_INPADDR_ADDRESS reload for operand I. */ +static HARD_REG_SET reload_reg_used_in_inpaddr_addr[MAX_RECOG_OPERANDS]; /* If reg is in use for a RELOAD_FOR_OUTPUT_ADDRESS reload for operand I. */ static HARD_REG_SET reload_reg_used_in_output_addr[MAX_RECOG_OPERANDS]; +/* If reg is in use for a RELOAD_FOR_OUTADDR_ADDRESS reload for operand I. */ +static HARD_REG_SET reload_reg_used_in_outaddr_addr[MAX_RECOG_OPERANDS]; /* If reg is in use for a RELOAD_FOR_INPUT reload for operand I. */ static HARD_REG_SET reload_reg_used_in_input[MAX_RECOG_OPERANDS]; /* If reg is in use for a RELOAD_FOR_OUTPUT reload for operand I. */ @@ -4207,10 +4384,18 @@ mark_reload_reg_in_use (regno, opnum, type, mode) SET_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i); break; + case RELOAD_FOR_INPADDR_ADDRESS: + SET_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], i); + break; + case RELOAD_FOR_OUTPUT_ADDRESS: SET_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i); break; + case RELOAD_FOR_OUTADDR_ADDRESS: + SET_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i); + break; + case RELOAD_FOR_OPERAND_ADDRESS: SET_HARD_REG_BIT (reload_reg_used_in_op_addr, i); break; @@ -4264,10 +4449,18 @@ clear_reload_reg_in_use (regno, opnum, type, mode) CLEAR_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i); break; + case RELOAD_FOR_INPADDR_ADDRESS: + CLEAR_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], i); + break; + case RELOAD_FOR_OUTPUT_ADDRESS: CLEAR_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i); break; + case RELOAD_FOR_OUTADDR_ADDRESS: + CLEAR_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i); + break; + case RELOAD_FOR_OPERAND_ADDRESS: CLEAR_HARD_REG_BIT (reload_reg_used_in_op_addr, i); break; @@ -4321,7 +4514,9 @@ reload_reg_free_p (regno, opnum, type) for (i = 0; i < reload_n_operands; i++) if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) return 0; @@ -4343,7 +4538,8 @@ reload_reg_free_p (regno, opnum, type) /* If it is used in a later operand's address, can't use it. */ for (i = opnum + 1; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)) + if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)) return 0; return 1; @@ -4351,7 +4547,21 @@ reload_reg_free_p (regno, opnum, type) case RELOAD_FOR_INPUT_ADDRESS: /* Can't use a register if it is used for an input address for this operand or used as an input in an earlier one. */ - if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], regno)) + if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno)) + return 0; + + for (i = 0; i < opnum; i++) + if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)) + return 0; + + return 1; + + case RELOAD_FOR_INPADDR_ADDRESS: + /* Can't use a register if it is used for an input address + address for this operand or used as an input in an earlier + one. */ + if (TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno)) return 0; for (i = 0; i < opnum; i++) @@ -4372,6 +4582,19 @@ reload_reg_free_p (regno, opnum, type) return 1; + case RELOAD_FOR_OUTADDR_ADDRESS: + /* Can't use a register if it is used for an output address + address for this operand or used as an output in this or a + later operand. */ + if (TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], regno)) + return 0; + + for (i = opnum; i < reload_n_operands; i++) + if (TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) + return 0; + + return 1; + case RELOAD_FOR_OPERAND_ADDRESS: for (i = 0; i < reload_n_operands; i++) if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)) @@ -4398,7 +4621,8 @@ reload_reg_free_p (regno, opnum, type) return 0; for (i = 0; i <= opnum; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)) + if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)) return 0; return 1; @@ -4452,12 +4676,14 @@ reload_reg_free_before_p (regno, opnum, type) the first place, since we know that it was allocated. */ case RELOAD_FOR_OUTPUT_ADDRESS: + case RELOAD_FOR_OUTADDR_ADDRESS: /* Earlier reloads are for earlier outputs or their addresses, any RELOAD_FOR_INSN reloads, any inputs or their addresses, or any RELOAD_FOR_OTHER_ADDRESS reloads (we know it can't conflict with RELOAD_OTHER).. */ for (i = 0; i < opnum; i++) if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) return 0; @@ -4466,6 +4692,7 @@ reload_reg_free_before_p (regno, opnum, type) for (i = 0; i < reload_n_operands; i++) if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)) return 0; @@ -4478,16 +4705,19 @@ reload_reg_free_before_p (regno, opnum, type) anything that can't be used for it, except that we've already tested for RELOAD_FOR_INSN objects. */ - if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], regno)) + if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], regno)) return 0; for (i = 0; i < opnum; i++) if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) return 0; for (i = 0; i < reload_n_operands; i++) if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)) return 0; @@ -4495,13 +4725,20 @@ reload_reg_free_before_p (regno, opnum, type) return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno); case RELOAD_FOR_OPERAND_ADDRESS: + /* Earlier reloads include RELOAD_FOR_OPADDR_ADDR reloads. */ + if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno)) + return 0; + + /* ... fall through ... */ + case RELOAD_FOR_OPADDR_ADDR: case RELOAD_FOR_INSN: /* These can't conflict with inputs, or each other, so all we have to test is input addresses and the addresses of OTHER items. */ for (i = 0; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)) + if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)) return 0; return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno); @@ -4512,16 +4749,19 @@ reload_reg_free_before_p (regno, opnum, type) with), and addresses of RELOAD_OTHER objects. */ for (i = 0; i <= opnum; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)) + if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)) return 0; return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno); case RELOAD_FOR_INPUT_ADDRESS: + case RELOAD_FOR_INPADDR_ADDRESS: /* Similarly, all we have to check is for use in earlier inputs' addresses. */ for (i = 0; i < opnum; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)) + if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)) return 0; return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno); @@ -4563,8 +4803,10 @@ reload_reg_reaches_end_p (regno, opnum, type) for (i = 0; i < reload_n_operands; i++) if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)) return 0; @@ -4573,6 +4815,7 @@ reload_reg_reaches_end_p (regno, opnum, type) && ! TEST_HARD_REG_BIT (reload_reg_used, regno)); case RELOAD_FOR_INPUT_ADDRESS: + case RELOAD_FOR_INPADDR_ADDRESS: /* Similar, except that we check only for this and subsequent inputs and the address of only subsequent inputs and we do not need to check for RELOAD_OTHER objects since they are known not to @@ -4583,11 +4826,13 @@ reload_reg_reaches_end_p (regno, opnum, type) return 0; for (i = opnum + 1; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)) + if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)) return 0; for (i = 0; i < reload_n_operands; i++) if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) return 0; @@ -4605,6 +4850,7 @@ reload_reg_reaches_end_p (regno, opnum, type) for (i = opnum + 1; i < reload_n_operands; i++) if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)) return 0; @@ -4615,6 +4861,7 @@ reload_reg_reaches_end_p (regno, opnum, type) for (i = 0; i < reload_n_operands; i++) if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) return 0; @@ -4623,6 +4870,7 @@ reload_reg_reaches_end_p (regno, opnum, type) case RELOAD_FOR_OPADDR_ADDR: for (i = 0; i < reload_n_operands; i++) if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno) || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) return 0; @@ -4639,10 +4887,12 @@ reload_reg_reaches_end_p (regno, opnum, type) case RELOAD_FOR_OUTPUT: case RELOAD_FOR_OUTPUT_ADDRESS: + case RELOAD_FOR_OUTADDR_ADDRESS: /* We already know these can't conflict with a later output. So the only thing to check are later output addresses. */ for (i = opnum + 1; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)) + if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) + || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)) return 0; return 1; @@ -4678,16 +4928,26 @@ reloads_conflict (r1, r2) || r2_type == RELOAD_FOR_OPERAND_ADDRESS || r2_type == RELOAD_FOR_OPADDR_ADDR || r2_type == RELOAD_FOR_INPUT - || (r2_type == RELOAD_FOR_INPUT_ADDRESS && r2_opnum > r1_opnum)); + || ((r2_type == RELOAD_FOR_INPUT_ADDRESS + || r2_type == RELOAD_FOR_INPADDR_ADDRESS) + && r2_opnum > r1_opnum)); case RELOAD_FOR_INPUT_ADDRESS: return ((r2_type == RELOAD_FOR_INPUT_ADDRESS && r1_opnum == r2_opnum) || (r2_type == RELOAD_FOR_INPUT && r2_opnum < r1_opnum)); + case RELOAD_FOR_INPADDR_ADDRESS: + return ((r2_type == RELOAD_FOR_INPADDR_ADDRESS && r1_opnum == r2_opnum) + || (r2_type == RELOAD_FOR_INPUT && r2_opnum < r1_opnum)); + case RELOAD_FOR_OUTPUT_ADDRESS: return ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS && r2_opnum == r1_opnum) || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum >= r1_opnum)); + case RELOAD_FOR_OUTADDR_ADDRESS: + return ((r2_type == RELOAD_FOR_OUTADDR_ADDRESS && r2_opnum == r1_opnum) + || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum >= r1_opnum)); + case RELOAD_FOR_OPERAND_ADDRESS: return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_INSN || r2_type == RELOAD_FOR_OPERAND_ADDRESS); @@ -4698,7 +4958,8 @@ reloads_conflict (r1, r2) case RELOAD_FOR_OUTPUT: return (r2_type == RELOAD_FOR_INSN || r2_type == RELOAD_FOR_OUTPUT - || (r2_type == RELOAD_FOR_OUTPUT_ADDRESS + || ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS + || r2_type == RELOAD_FOR_OUTADDR_ADDRESS) && r2_opnum >= r1_opnum)); case RELOAD_FOR_INSN: @@ -4960,7 +5221,9 @@ choose_reload_regs (insn, avoid_return_reg) int save_reload_spill_index[MAX_RELOADS]; HARD_REG_SET save_reload_reg_used; HARD_REG_SET save_reload_reg_used_in_input_addr[MAX_RECOG_OPERANDS]; + HARD_REG_SET save_reload_reg_used_in_inpaddr_addr[MAX_RECOG_OPERANDS]; HARD_REG_SET save_reload_reg_used_in_output_addr[MAX_RECOG_OPERANDS]; + HARD_REG_SET save_reload_reg_used_in_outaddr_addr[MAX_RECOG_OPERANDS]; HARD_REG_SET save_reload_reg_used_in_input[MAX_RECOG_OPERANDS]; HARD_REG_SET save_reload_reg_used_in_output[MAX_RECOG_OPERANDS]; HARD_REG_SET save_reload_reg_used_in_op_addr; @@ -4985,13 +5248,15 @@ choose_reload_regs (insn, avoid_return_reg) CLEAR_HARD_REG_SET (reload_reg_used_in_output[i]); CLEAR_HARD_REG_SET (reload_reg_used_in_input[i]); CLEAR_HARD_REG_SET (reload_reg_used_in_input_addr[i]); + CLEAR_HARD_REG_SET (reload_reg_used_in_inpaddr_addr[i]); CLEAR_HARD_REG_SET (reload_reg_used_in_output_addr[i]); + CLEAR_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i]); } #ifdef SMALL_REGISTER_CLASSES /* Don't bother with avoiding the return reg if we have no mandatory reload that could use it. */ - if (avoid_return_reg) + if (SMALL_REGISTER_CLASSES && avoid_return_reg) { int do_avoid = 0; int regno = REGNO (avoid_return_reg); @@ -5024,7 +5289,8 @@ choose_reload_regs (insn, avoid_return_reg) { int tem = 0; #ifdef SMALL_REGISTER_CLASSES - int tem = (avoid_return_reg != 0); + if (SMALL_REGISTER_CLASSES) + tem = (avoid_return_reg != 0); #endif for (j = 0; j < n_reloads; j++) if (! reload_optional[j] @@ -5041,7 +5307,7 @@ choose_reload_regs (insn, avoid_return_reg) #ifdef SMALL_REGISTER_CLASSES /* Don't use the subroutine call return reg for a reload if we are supposed to avoid it. */ - if (avoid_return_reg) + if (SMALL_REGISTER_CLASSES && avoid_return_reg) { int regno = REGNO (avoid_return_reg); int nregs @@ -5123,8 +5389,12 @@ choose_reload_regs (insn, avoid_return_reg) reload_reg_used_in_input[i]); COPY_HARD_REG_SET (save_reload_reg_used_in_input_addr[i], reload_reg_used_in_input_addr[i]); + COPY_HARD_REG_SET (save_reload_reg_used_in_inpaddr_addr[i], + reload_reg_used_in_inpaddr_addr[i]); COPY_HARD_REG_SET (save_reload_reg_used_in_output_addr[i], reload_reg_used_in_output_addr[i]); + COPY_HARD_REG_SET (save_reload_reg_used_in_outaddr_addr[i], + reload_reg_used_in_outaddr_addr[i]); } /* If -O, try first with inheritance, then turning it off. @@ -5502,8 +5772,12 @@ choose_reload_regs (insn, avoid_return_reg) save_reload_reg_used_in_output[i]); COPY_HARD_REG_SET (reload_reg_used_in_input_addr[i], save_reload_reg_used_in_input_addr[i]); + COPY_HARD_REG_SET (reload_reg_used_in_inpaddr_addr[i], + save_reload_reg_used_in_inpaddr_addr[i]); COPY_HARD_REG_SET (reload_reg_used_in_output_addr[i], save_reload_reg_used_in_output_addr[i]); + COPY_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i], + save_reload_reg_used_in_outaddr_addr[i]); } } @@ -5677,8 +5951,9 @@ merge_assigned_reloads (insn) && reg_overlap_mentioned_for_reload_p (reload_in[j], reload_in[i])) reload_when_needed[j] - = reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS - ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER; + = ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS + || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS) + ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER); } } } @@ -5695,8 +5970,10 @@ emit_reload_insns (insn) rtx other_input_address_reload_insns = 0; rtx other_input_reload_insns = 0; rtx input_address_reload_insns[MAX_RECOG_OPERANDS]; + rtx inpaddr_address_reload_insns[MAX_RECOG_OPERANDS]; rtx output_reload_insns[MAX_RECOG_OPERANDS]; rtx output_address_reload_insns[MAX_RECOG_OPERANDS]; + rtx outaddr_address_reload_insns[MAX_RECOG_OPERANDS]; rtx operand_reload_insns = 0; rtx other_operand_reload_insns = 0; rtx other_output_reload_insns[MAX_RECOG_OPERANDS]; @@ -5708,7 +5985,9 @@ emit_reload_insns (insn) for (j = 0; j < reload_n_operands; j++) input_reload_insns[j] = input_address_reload_insns[j] + = inpaddr_address_reload_insns[j] = output_reload_insns[j] = output_address_reload_insns[j] + = outaddr_address_reload_insns[j] = other_output_reload_insns[j] = 0; /* Now output the instructions to copy the data into and out of the @@ -5903,9 +6182,15 @@ emit_reload_insns (insn) case RELOAD_FOR_INPUT_ADDRESS: where = &input_address_reload_insns[reload_opnum[j]]; break; + case RELOAD_FOR_INPADDR_ADDRESS: + where = &inpaddr_address_reload_insns[reload_opnum[j]]; + break; case RELOAD_FOR_OUTPUT_ADDRESS: where = &output_address_reload_insns[reload_opnum[j]]; break; + case RELOAD_FOR_OUTADDR_ADDRESS: + where = &outaddr_address_reload_insns[reload_opnum[j]]; + break; case RELOAD_FOR_OPERAND_ADDRESS: where = &operand_reload_insns; break; @@ -5974,8 +6259,8 @@ emit_reload_insns (insn) SET_DEST (PATTERN (temp)) = reloadreg; /* If these are the only uses of the pseudo reg, pretend for GDB it lives in the reload reg we used. */ - if (reg_n_deaths[REGNO (old)] == 1 - && reg_n_sets[REGNO (old)] == 1) + if (REG_N_DEATHS (REGNO (old)) == 1 + && REG_N_SETS (REGNO (old)) == 1) { reg_renumber[REGNO (old)] = REGNO (reload_reg_rtx[j]); alter_reg (REGNO (old), -1); @@ -6508,8 +6793,9 @@ emit_reload_insns (insn) RELOAD_OTHER reloads. - For each operand, any RELOAD_FOR_INPUT_ADDRESS reloads followed by - the RELOAD_FOR_INPUT reload for the operand. + For each operand, any RELOAD_FOR_INPADDR_ADDRESS reloads followed + by any RELOAD_FOR_INPUT_ADDRESS reloads followed by the + RELOAD_FOR_INPUT reload for the operand. RELOAD_FOR_OPADDR_ADDRS reloads. @@ -6517,16 +6803,18 @@ emit_reload_insns (insn) After the insn being reloaded, we write the following: - For each operand, any RELOAD_FOR_OUTPUT_ADDRESS reload followed by - the RELOAD_FOR_OUTPUT reload, followed by any RELOAD_OTHER output - reloads for the operand. The RELOAD_OTHER output reloads are output - in descending order by reload number. */ + For each operand, any RELOAD_FOR_OUTADDR_ADDRESS reloads followed + by any RELOAD_FOR_OUTPUT_ADDRESS reload followed by the + RELOAD_FOR_OUTPUT reload, followed by any RELOAD_OTHER output + reloads for the operand. The RELOAD_OTHER output reloads are + output in descending order by reload number. */ emit_insns_before (other_input_address_reload_insns, before_insn); emit_insns_before (other_input_reload_insns, before_insn); for (j = 0; j < reload_n_operands; j++) { + emit_insns_before (inpaddr_address_reload_insns[j], before_insn); emit_insns_before (input_address_reload_insns[j], before_insn); emit_insns_before (input_reload_insns[j], before_insn); } @@ -6536,6 +6824,7 @@ emit_reload_insns (insn) for (j = 0; j < reload_n_operands; j++) { + emit_insns_before (outaddr_address_reload_insns[j], following_insn); emit_insns_before (output_address_reload_insns[j], following_insn); emit_insns_before (output_reload_insns[j], following_insn); emit_insns_before (other_output_reload_insns[j], following_insn); @@ -7009,8 +7298,8 @@ delete_output_reload (insn, j, output_reload_insn) /* See if the pseudo reg has been completely replaced with reload regs. If so, delete the store insn and forget we had a stack slot for the pseudo. */ - else if (reg_n_deaths[REGNO (reg)] == 1 - && reg_basic_block[REGNO (reg)] >= 0 + else if (REG_N_DEATHS (REGNO (reg)) == 1 + && REG_BASIC_BLOCK (REGNO (reg)) >= 0 && find_regno_note (insn, REG_DEAD, REGNO (reg))) { rtx i2; @@ -7263,3 +7552,813 @@ count_occurrences (x, find) } return count; } + +/* This array holds values which are equivalent to a hard register + during reload_cse_regs. Each array element is an EXPR_LIST of + values. Each time a hard register is set, we set the corresponding + array element to the value. Each time a hard register is copied + into memory, we add the memory location to the corresponding array + element. We don't store values or memory addresses with side + effects in this array. + + If the value is a CONST_INT, then the mode of the containing + EXPR_LIST is the mode in which that CONST_INT was referenced. + + We sometimes clobber a specific entry in a list. In that case, we + just set XEXP (list-entry, 0) to 0. */ + +static rtx *reg_values; + +/* This is a preallocated REG rtx which we use as a temporary in + reload_cse_invalidate_regno, so that we don't need to allocate a + new one each time through a loop in that function. */ + +static rtx invalidate_regno_rtx; + +/* Invalidate any entries in reg_values which depend on REGNO, + including those for REGNO itself. This is called if REGNO is + changing. If CLOBBER is true, then always forget anything we + currently know about REGNO. MODE is the mode of the assignment to + REGNO, which is used to determine how many hard registers are being + changed. If MODE is VOIDmode, then only REGNO is being changed; + this is used when invalidating call clobbered registers across a + call. */ + +static void +reload_cse_invalidate_regno (regno, mode, clobber) + int regno; + enum machine_mode mode; + int clobber; +{ + int endregno; + register int i; + + /* Our callers don't always go through true_regnum; we may see a + pseudo-register here from a CLOBBER or the like. We probably + won't ever see a pseudo-register that has a real register number, + for we check anyhow for safety. */ + if (regno >= FIRST_PSEUDO_REGISTER) + regno = reg_renumber[regno]; + if (regno < 0) + return; + + if (mode == VOIDmode) + endregno = regno + 1; + else + endregno = regno + HARD_REGNO_NREGS (regno, mode); + + if (clobber) + for (i = regno; i < endregno; i++) + reg_values[i] = 0; + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + rtx x; + + for (x = reg_values[i]; x; x = XEXP (x, 1)) + { + if (XEXP (x, 0) != 0 + && refers_to_regno_p (regno, endregno, XEXP (x, 0), NULL_PTR)) + { + /* If this is the only entry on the list, clear + reg_values[i]. Otherwise, just clear this entry on + the list. */ + if (XEXP (x, 1) == 0 && x == reg_values[i]) + { + reg_values[i] = 0; + break; + } + XEXP (x, 0) = 0; + } + } + } + + /* We must look at earlier registers, in case REGNO is part of a + multi word value but is not the first register. If an earlier + register has a value in a mode which overlaps REGNO, then we must + invalidate that earlier register. Note that we do not need to + check REGNO or later registers (we must not check REGNO itself, + because we would incorrectly conclude that there was a conflict). */ + + for (i = 0; i < regno; i++) + { + rtx x; + + for (x = reg_values[i]; x; x = XEXP (x, 1)) + { + if (XEXP (x, 0) != 0) + { + PUT_MODE (invalidate_regno_rtx, GET_MODE (x)); + REGNO (invalidate_regno_rtx) = i; + if (refers_to_regno_p (regno, endregno, invalidate_regno_rtx, + NULL_PTR)) + { + reload_cse_invalidate_regno (i, VOIDmode, 1); + break; + } + } + } + } +} + +/* The memory at address (plus MEM_BASE MEM_OFFSET), where MEM_OFFSET + is a CONST_INT, is being changed. MEM_MODE is the mode of the + memory reference. Return whether this change will invalidate VAL. */ + +static int +reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode, val) + rtx mem_base; + rtx mem_offset; + enum machine_mode mem_mode; + rtx val; +{ + enum rtx_code code; + char *fmt; + int i; + + code = GET_CODE (val); + switch (code) + { + /* Get rid of a few simple cases quickly. */ + case REG: + case PC: + case CC0: + case SCRATCH: + case CONST: + case CONST_INT: + case CONST_DOUBLE: + case SYMBOL_REF: + case LABEL_REF: + return 0; + + case MEM: + { + rtx val_base, val_offset; + + if (mem_mode == BLKmode || GET_MODE (val) == BLKmode) + return 1; + + val_offset = const0_rtx; + val_base = eliminate_constant_term (XEXP (val, 0), &val_offset); + + /* If MEM_BASE and VAL_BASE are the same, but the offsets do + not overlap, then we do not have a conflict on this MEM. + For complete safety, we still need to check that VAL_BASE + itself does not contain an overlapping MEM. + + We can't simplify the check to just OFFSET + SIZE <= + OTHER_OFFSET, because SIZE might cause OFFSET to wrap from + positive to negative. If we used unsigned arithmetic, we + would have the same problem wrapping around zero. */ + + if (rtx_equal_p (mem_base, val_base) + && ((INTVAL (mem_offset) < INTVAL (val_offset) + && (INTVAL (mem_offset) + GET_MODE_SIZE (mem_mode) + <= INTVAL (val_offset))) + || (INTVAL (val_offset) < INTVAL (mem_offset) + && (INTVAL (val_offset) + GET_MODE_SIZE (GET_MODE (val)) + <= INTVAL (mem_offset))))) + return reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode, + val_base); + + return 1; + } + + default: + break; + } + + fmt = GET_RTX_FORMAT (code); + + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + if (reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode, + XEXP (val, i))) + return 1; + } + else if (fmt[i] == 'E') + { + int j; + + for (j = 0; j < XVECLEN (val, i); j++) + if (reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode, + XVECEXP (val, i, j))) + return 1; + } + } + + return 0; +} + +/* Invalidate any entries in reg_values which are changed because of a + store to MEM_RTX. If this is called because of a non-const call + instruction, MEM_RTX is (mem:BLK const0_rtx). */ + +static void +reload_cse_invalidate_mem (mem_rtx) + rtx mem_rtx; +{ + register int i; + rtx mem_base, mem_offset; + enum machine_mode mem_mode; + + /* We detect certain cases where memory addresses can not conflict: + if they use the same register, and the offsets do not overlap. */ + + mem_offset = const0_rtx; + mem_base = eliminate_constant_term (XEXP (mem_rtx, 0), &mem_offset); + mem_mode = GET_MODE (mem_rtx); + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + rtx x; + + for (x = reg_values[i]; x; x = XEXP (x, 1)) + { + if (XEXP (x, 0) != 0 + && reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode, + XEXP (x, 0))) + { + /* If this is the only entry on the list, clear + reg_values[i]. Otherwise, just clear this entry on + the list. */ + if (XEXP (x, 1) == 0 && x == reg_values[i]) + { + reg_values[i] = 0; + break; + } + XEXP (x, 0) = 0; + } + } + } +} + +/* Invalidate DEST, which is being assigned to or clobbered. The + second parameter exists so that this function can be passed to + note_stores; it is ignored. */ + +static void +reload_cse_invalidate_rtx (dest, ignore) + rtx dest; + rtx ignore; +{ + while (GET_CODE (dest) == STRICT_LOW_PART + || GET_CODE (dest) == SIGN_EXTRACT + || GET_CODE (dest) == ZERO_EXTRACT + || GET_CODE (dest) == SUBREG) + dest = XEXP (dest, 0); + + if (GET_CODE (dest) == REG) + reload_cse_invalidate_regno (REGNO (dest), GET_MODE (dest), 1); + else if (GET_CODE (dest) == MEM) + reload_cse_invalidate_mem (dest); +} + +/* Do a very simple CSE pass over the hard registers. + + This function detects no-op moves where we happened to assign two + different pseudo-registers to the same hard register, and then + copied one to the other. Reload will generate a useless + instruction copying a register to itself. + + This function also detects cases where we load a value from memory + into two different registers, and (if memory is more expensive than + registers) changes it to simply copy the first register into the + second register. */ + +static void +reload_cse_regs (first) + rtx first; +{ + char *firstobj; + rtx callmem; + register int i; + rtx insn; + + reg_values = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx)); + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + reg_values[i] = 0; + + /* Create our EXPR_LIST structures on reload_obstack, so that we can + free them when we are done. */ + push_obstacks (&reload_obstack, &reload_obstack); + firstobj = (char *) obstack_alloc (&reload_obstack, 0); + + /* We pass this to reload_cse_invalidate_mem to invalidate all of + memory for a non-const call instruction. */ + callmem = gen_rtx (MEM, BLKmode, const0_rtx); + + /* This is used in reload_cse_invalidate_regno to avoid consing a + new REG in a loop in that function. */ + invalidate_regno_rtx = gen_rtx (REG, VOIDmode, 0); + + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + rtx body; + + if (GET_CODE (insn) == CODE_LABEL) + { + /* Forget all the register values at a code label. We don't + try to do anything clever around jumps. */ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + reg_values[i] = 0; + + continue; + } + +#ifdef NON_SAVING_SETJMP + if (NON_SAVING_SETJMP && GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP) + { + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + reg_values[i] = 0; + + continue; + } +#endif + + if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') + continue; + + /* If this is a call instruction, forget anything stored in a + call clobbered register, or, if this is not a const call, in + memory. */ + if (GET_CODE (insn) == CALL_INSN) + { + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (call_used_regs[i]) + reload_cse_invalidate_regno (i, VOIDmode, 1); + + if (! CONST_CALL_P (insn)) + reload_cse_invalidate_mem (callmem); + } + + body = PATTERN (insn); + if (GET_CODE (body) == SET) + { + if (reload_cse_noop_set_p (body, insn)) + { + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + + /* We're done with this insn. */ + continue; + } + + reload_cse_simplify_set (body, insn); + reload_cse_record_set (body, body); + } + else if (GET_CODE (body) == PARALLEL) + { + int delete; + + /* If every action in a PARALLEL is a noop, we can delete + the entire PARALLEL. */ + for (i = XVECLEN (body, 0) - 1; i >= 0; --i) + if (GET_CODE (XVECEXP (body, 0, i)) != SET + || ! reload_cse_noop_set_p (XVECEXP (body, 0, i), insn)) + break; + if (i < 0) + { + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + + /* We're done with this insn. */ + continue; + } + + /* Look through the PARALLEL and record the values being + set, if possible. Also handle any CLOBBERs. */ + for (i = XVECLEN (body, 0) - 1; i >= 0; --i) + { + rtx x = XVECEXP (body, 0, i); + + if (GET_CODE (x) == SET) + reload_cse_record_set (x, body); + else + note_stores (x, reload_cse_invalidate_rtx); + } + } + else + note_stores (body, reload_cse_invalidate_rtx); + +#ifdef AUTO_INC_DEC + /* Clobber any registers which appear in REG_INC notes. We + could keep track of the changes to their values, but it is + unlikely to help. */ + { + rtx x; + + for (x = REG_NOTES (insn); x; x = XEXP (x, 1)) + if (REG_NOTE_KIND (x) == REG_INC) + reload_cse_invalidate_rtx (XEXP (x, 0), NULL_RTX); + } +#endif + + /* Look for any CLOBBERs in CALL_INSN_FUNCTION_USAGE, but only + after we have processed the insn. */ + if (GET_CODE (insn) == CALL_INSN) + { + rtx x; + + for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1)) + if (GET_CODE (XEXP (x, 0)) == CLOBBER) + reload_cse_invalidate_rtx (XEXP (XEXP (x, 0), 0), NULL_RTX); + } + } + + /* Free all the temporary structures we created, and go back to the + regular obstacks. */ + obstack_free (&reload_obstack, firstobj); + pop_obstacks (); +} + +/* Return whether the values known for REGNO are equal to VAL. MODE + is the mode of the object that VAL is being copied to; this matters + if VAL is a CONST_INT. */ + +static int +reload_cse_regno_equal_p (regno, val, mode) + int regno; + rtx val; + enum machine_mode mode; +{ + rtx x; + + if (val == 0) + return 0; + + for (x = reg_values[regno]; x; x = XEXP (x, 1)) + if (XEXP (x, 0) != 0 + && rtx_equal_p (XEXP (x, 0), val) + && (GET_CODE (val) != CONST_INT + || mode == GET_MODE (x) + || (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x)) + /* On a big endian machine if the value spans more than + one register then this register holds the high part of + it and we can't use it. + + ??? We should also compare with the high part of the + value. */ + && !(WORDS_BIG_ENDIAN + && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1) + && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), + GET_MODE_BITSIZE (GET_MODE (x)))))) + return 1; + + return 0; +} + +/* See whether a single set is a noop. SET is the set instruction we + are should check, and INSN is the instruction from which it came. */ + +static int +reload_cse_noop_set_p (set, insn) + rtx set; + rtx insn; +{ + rtx src, dest; + enum machine_mode dest_mode; + int dreg, sreg; + int ret; + + src = SET_SRC (set); + dest = SET_DEST (set); + dest_mode = GET_MODE (dest); + + if (side_effects_p (src)) + return 0; + + dreg = true_regnum (dest); + sreg = true_regnum (src); + + /* Check for setting a register to itself. In this case, we don't + have to worry about REG_DEAD notes. */ + if (dreg >= 0 && dreg == sreg) + return 1; + + ret = 0; + if (dreg >= 0) + { + /* Check for setting a register to itself. */ + if (dreg == sreg) + ret = 1; + + /* Check for setting a register to a value which we already know + is in the register. */ + else if (reload_cse_regno_equal_p (dreg, src, dest_mode)) + ret = 1; + + /* Check for setting a register DREG to another register SREG + where SREG is equal to a value which is already in DREG. */ + else if (sreg >= 0) + { + rtx x; + + for (x = reg_values[sreg]; x; x = XEXP (x, 1)) + { + rtx tmp; + + if (XEXP (x, 0) == 0) + continue; + + if (dest_mode == GET_MODE (x)) + tmp = XEXP (x, 0); + else if (GET_MODE_BITSIZE (dest_mode) + < GET_MODE_BITSIZE (GET_MODE (x))) + tmp = gen_lowpart_common (dest_mode, XEXP (x, 0)); + else + continue; + + if (tmp + && reload_cse_regno_equal_p (dreg, tmp, dest_mode)) + { + ret = 1; + break; + } + } + } + } + else if (GET_CODE (dest) == MEM) + { + /* Check for storing a register to memory when we know that the + register is equivalent to the memory location. */ + if (sreg >= 0 + && reload_cse_regno_equal_p (sreg, dest, dest_mode) + && ! side_effects_p (dest)) + ret = 1; + } + + /* If we can delete this SET, then we need to look for an earlier + REG_DEAD note on DREG, and remove it if it exists. */ + if (ret) + { + if (! find_regno_note (insn, REG_UNUSED, dreg)) + { + rtx trial; + + for (trial = prev_nonnote_insn (insn); + (trial + && GET_CODE (trial) != CODE_LABEL + && GET_CODE (trial) != BARRIER); + trial = prev_nonnote_insn (trial)) + { + if (find_regno_note (trial, REG_DEAD, dreg)) + { + remove_death (dreg, trial); + break; + } + } + } + } + + return ret; +} + +/* Try to simplify a single SET instruction. SET is the set pattern. + INSN is the instruction it came from. */ + +static void +reload_cse_simplify_set (set, insn) + rtx set; + rtx insn; +{ + int dreg; + rtx src; + enum machine_mode dest_mode; + enum reg_class dclass; + register int i; + + /* We only handle one case: if we set a register to a value which is + not a register, we try to find that value in some other register + and change the set into a register copy. */ + + dreg = true_regnum (SET_DEST (set)); + if (dreg < 0) + return; + + src = SET_SRC (set); + if (side_effects_p (src) || true_regnum (src) >= 0) + return; + + /* If memory loads are cheaper than register copies, don't change + them. */ + if (GET_CODE (src) == MEM && MEMORY_MOVE_COST (GET_MODE (src)) < 2) + return; + + dest_mode = GET_MODE (SET_DEST (set)); + dclass = REGNO_REG_CLASS (dreg); + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + if (i != dreg + && REGISTER_MOVE_COST (REGNO_REG_CLASS (i), dclass) == 2 + && reload_cse_regno_equal_p (i, src, dest_mode)) + { + int validated; + + /* Pop back to the real obstacks while changing the insn. */ + pop_obstacks (); + + validated = validate_change (insn, &SET_SRC (set), + gen_rtx (REG, dest_mode, i), 0); + + /* Go back to the obstack we are using for temporary + storage. */ + push_obstacks (&reload_obstack, &reload_obstack); + + if (validated) + { + /* We need to look for an earlier REG_DEAD note on I, + and remove it if it exists. */ + if (! find_regno_note (insn, REG_UNUSED, i)) + { + rtx trial; + + for (trial = prev_nonnote_insn (insn); + (trial + && GET_CODE (trial) != CODE_LABEL + && GET_CODE (trial) != BARRIER); + trial = prev_nonnote_insn (trial)) + { + if (find_regno_note (trial, REG_DEAD, i)) + { + remove_death (i, trial); + break; + } + } + } + + return; + } + } + } +} + +/* These two variables are used to pass information from + reload_cse_record_set to reload_cse_check_clobber. */ + +static int reload_cse_check_clobbered; +static rtx reload_cse_check_src; + +/* See if DEST overlaps with RELOAD_CSE_CHECK_SRC. If it does, set + RELOAD_CSE_CHECK_CLOBBERED. This is called via note_stores. The + second argument, which is passed by note_stores, is ignored. */ + +static void +reload_cse_check_clobber (dest, ignore) + rtx dest; + rtx ignore; +{ + if (reg_overlap_mentioned_p (dest, reload_cse_check_src)) + reload_cse_check_clobbered = 1; +} + +/* Record the result of a SET instruction. SET is the set pattern. + BODY is the pattern of the insn that it came from. */ + +static void +reload_cse_record_set (set, body) + rtx set; + rtx body; +{ + rtx dest, src, x; + int dreg, sreg; + enum machine_mode dest_mode; + + dest = SET_DEST (set); + src = SET_SRC (set); + dreg = true_regnum (dest); + sreg = true_regnum (src); + dest_mode = GET_MODE (dest); + + /* Some machines don't define AUTO_INC_DEC, but they still use push + instructions. We need to catch that case here in order to + invalidate the stack pointer correctly. Note that invalidating + the stack pointer is different from invalidating DEST. */ + x = dest; + while (GET_CODE (x) == SUBREG + || GET_CODE (x) == ZERO_EXTRACT + || GET_CODE (x) == SIGN_EXTRACT + || GET_CODE (x) == STRICT_LOW_PART) + x = XEXP (x, 0); + if (push_operand (x, GET_MODE (x))) + { + reload_cse_invalidate_rtx (stack_pointer_rtx, NULL_RTX); + reload_cse_invalidate_rtx (dest, NULL_RTX); + return; + } + + /* We can only handle an assignment to a register, or a store of a + register to a memory location. For other cases, we just clobber + the destination. We also have to just clobber if there are side + effects in SRC or DEST. */ + if ((dreg < 0 && GET_CODE (dest) != MEM) + || side_effects_p (src) + || side_effects_p (dest)) + { + reload_cse_invalidate_rtx (dest, NULL_RTX); + return; + } + +#ifdef HAVE_cc0 + /* We don't try to handle values involving CC, because it's a pain + to keep track of when they have to be invalidated. */ + if (reg_mentioned_p (cc0_rtx, src) + || reg_mentioned_p (cc0_rtx, dest)) + { + reload_cse_invalidate_rtx (dest, NULL_RTX); + return; + } +#endif + + /* If BODY is a PARALLEL, then we need to see whether the source of + SET is clobbered by some other instruction in the PARALLEL. */ + if (GET_CODE (body) == PARALLEL) + { + int i; + + for (i = XVECLEN (body, 0) - 1; i >= 0; --i) + { + rtx x; + + x = XVECEXP (body, 0, i); + if (x == set) + continue; + + reload_cse_check_clobbered = 0; + reload_cse_check_src = src; + note_stores (x, reload_cse_check_clobber); + if (reload_cse_check_clobbered) + { + reload_cse_invalidate_rtx (dest, NULL_RTX); + return; + } + } + } + + if (dreg >= 0) + { + int i; + + /* This is an assignment to a register. Update the value we + have stored for the register. */ + if (sreg >= 0) + { + rtx x; + + /* This is a copy from one register to another. Any values + which were valid for SREG are now valid for DREG. If the + mode changes, we use gen_lowpart_common to extract only + the part of the value that is copied. */ + reg_values[dreg] = 0; + for (x = reg_values[sreg]; x; x = XEXP (x, 1)) + { + rtx tmp; + + if (XEXP (x, 0) == 0) + continue; + if (dest_mode == GET_MODE (XEXP (x, 0))) + tmp = XEXP (x, 0); + else if (GET_MODE_BITSIZE (dest_mode) + > GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))) + continue; + else + tmp = gen_lowpart_common (dest_mode, XEXP (x, 0)); + if (tmp) + reg_values[dreg] = gen_rtx (EXPR_LIST, dest_mode, tmp, + reg_values[dreg]); + } + } + else + reg_values[dreg] = gen_rtx (EXPR_LIST, dest_mode, src, NULL_RTX); + + /* We've changed DREG, so invalidate any values held by other + registers that depend upon it. */ + reload_cse_invalidate_regno (dreg, dest_mode, 0); + + /* If this assignment changes more than one hard register, + forget anything we know about the others. */ + for (i = 1; i < HARD_REGNO_NREGS (dreg, dest_mode); i++) + reg_values[dreg + i] = 0; + } + else if (GET_CODE (dest) == MEM) + { + /* Invalidate conflicting memory locations. */ + reload_cse_invalidate_mem (dest); + + /* If we're storing a register to memory, add DEST to the list + in REG_VALUES. */ + if (sreg >= 0 && ! side_effects_p (dest)) + reg_values[sreg] = gen_rtx (EXPR_LIST, dest_mode, dest, + reg_values[sreg]); + } + else + { + /* We should have bailed out earlier. */ + abort (); + } +}