X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Freload.c;h=a2642aa7349973d080ff19a37fa9f5329de1cd52;hb=a322b452ba1d7ea97d01a35a501812f13cddfb6f;hp=579cb1b9f70cad328e3283b8b3ac8aa21013d12a;hpb=2e6d14e821c5d443c3b1b9bf9986465316e60f51;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/reload.c b/gcc/reload.c index 579cb1b9f70..a2642aa7349 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -1,6 +1,6 @@ /* Search an insn for pseudo regs that must be in hard regs and are not. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GCC. @@ -88,6 +88,8 @@ a register with any other reload. */ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "rtl.h" #include "tm_p.h" #include "insn-config.h" @@ -240,9 +242,11 @@ static int push_secondary_reload PARAMS ((int, rtx, int, int, enum reg_class, enum machine_mode, enum reload_type, enum insn_code *)); #endif -static enum reg_class find_valid_class PARAMS ((enum machine_mode, int)); -static int reload_inner_reg_of_subreg PARAMS ((rtx, enum machine_mode)); +static enum reg_class find_valid_class PARAMS ((enum machine_mode, int, + unsigned int)); +static int reload_inner_reg_of_subreg PARAMS ((rtx, enum machine_mode, int)); static void push_replacement PARAMS ((rtx *, int, enum machine_mode)); +static void dup_replacements PARAMS ((rtx *, rtx *)); static void combine_reloads PARAMS ((void)); static int find_reusable_reload PARAMS ((rtx *, rtx, enum reg_class, enum reload_type, int, int)); @@ -256,6 +260,7 @@ static int alternative_allows_memconst PARAMS ((const char *, int)); static rtx find_reloads_toplev PARAMS ((rtx, int, enum reload_type, int, int, rtx, int *)); static rtx make_memloc PARAMS ((rtx, int)); +static int maybe_memory_address_p PARAMS ((enum machine_mode, rtx, rtx *)); static int find_reloads_address PARAMS ((enum machine_mode, rtx *, rtx, rtx *, int, enum reload_type, int, rtx)); static rtx subst_reg_equivs PARAMS ((rtx, rtx)); @@ -266,14 +271,15 @@ static int find_reloads_address_1 PARAMS ((enum machine_mode, rtx, int, rtx *, static void find_reloads_address_part PARAMS ((rtx, rtx *, enum reg_class, enum machine_mode, int, enum reload_type, int)); -static rtx find_reloads_subreg_address PARAMS ((rtx, int, int, enum reload_type, - int, rtx)); +static rtx find_reloads_subreg_address PARAMS ((rtx, int, int, + enum reload_type, int, rtx)); +static void copy_replacements_1 PARAMS ((rtx *, rtx *, int)); static int find_inc_amount PARAMS ((rtx, rtx)); #ifdef HAVE_SECONDARY_RELOADS /* Determine if any secondary reloads are needed for loading (if IN_P is - non-zero) or storing (if IN_P is zero) X to or from a reload register of + nonzero) or storing (if IN_P is zero) X to or from a reload register of register class RELOAD_CLASS in mode RELOAD_MODE. If secondary reloads are needed, push them. @@ -365,7 +371,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode, if (icode != CODE_FOR_nothing) { - /* If IN_P is non-zero, the reload register will be the output in + /* If IN_P is nonzero, the reload register will be the output in operand 0. If IN_P is zero, the reload register will be the input in operand 1. Outputs should have an initial "=", which we must skip. */ @@ -376,11 +382,13 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode, insn_class = ALL_REGS; else { - char insn_letter - = insn_data[(int) icode].operand[!in_p].constraint[in_p]; + const char *insn_constraint + = &insn_data[(int) icode].operand[!in_p].constraint[in_p]; + char insn_letter = *insn_constraint; insn_class = (insn_letter == 'r' ? GENERAL_REGS - : REG_CLASS_FROM_LETTER ((unsigned char) insn_letter)); + : REG_CLASS_FROM_CONSTRAINT ((unsigned char) insn_letter, + insn_constraint)); if (insn_class == NO_REGS) abort (); @@ -398,11 +406,14 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode, mode = insn_data[(int) icode].operand[2].mode; else { - char t_letter = insn_data[(int) icode].operand[2].constraint[2]; + const char *t_constraint + = &insn_data[(int) icode].operand[2].constraint[2]; + char t_letter = *t_constraint; class = insn_class; t_mode = insn_data[(int) icode].operand[2].mode; t_class = (t_letter == 'r' ? GENERAL_REGS - : REG_CLASS_FROM_LETTER ((unsigned char) t_letter)); + : REG_CLASS_FROM_CONSTRAINT ((unsigned char) t_letter, + t_constraint)); t_icode = icode; icode = CODE_FOR_nothing; } @@ -642,7 +653,7 @@ get_secondary_mem (x, mode, opnum, type) : type == RELOAD_FOR_OUTPUT ? RELOAD_FOR_OUTPUT_ADDRESS : RELOAD_OTHER); - find_reloads_address (mode, (rtx*)0, XEXP (loc, 0), &XEXP (loc, 0), + find_reloads_address (mode, &loc, XEXP (loc, 0), &XEXP (loc, 0), opnum, type, 0, 0); } @@ -660,17 +671,22 @@ clear_secondary_mem () #endif /* SECONDARY_MEMORY_NEEDED */ /* Find the largest class for which every register number plus N is valid in - M1 (if in range). Abort if no such class exists. */ + M1 (if in range) and is cheap to move into REGNO. + Abort if no such class exists. */ static enum reg_class -find_valid_class (m1, n) +find_valid_class (m1, n, dest_regno) enum machine_mode m1 ATTRIBUTE_UNUSED; int n; + unsigned int dest_regno ATTRIBUTE_UNUSED; { + int best_cost = -1; int class; int regno; enum reg_class best_class = NO_REGS; + enum reg_class dest_class ATTRIBUTE_UNUSED = REGNO_REG_CLASS (dest_regno); unsigned int best_size = 0; + int cost; for (class = 1; class < N_REG_CLASSES; class++) { @@ -681,8 +697,18 @@ find_valid_class (m1, n) && ! HARD_REGNO_MODE_OK (regno + n, m1)) bad = 1; - if (! bad && reg_class_size[class] > best_size) - best_class = class, best_size = reg_class_size[class]; + if (bad) + continue; + cost = REGISTER_MOVE_COST (m1, class, dest_class); + + if ((reg_class_size[class] > best_size + && (best_cost < 0 || best_cost >= cost)) + || best_cost > cost) + { + best_class = class; + best_size = reg_class_size[class]; + best_cost = REGISTER_MOVE_COST (m1, class, dest_class); + } } if (best_size == 0) @@ -777,9 +803,10 @@ find_reusable_reload (p_in, out, class, type, opnum, dont_share) SUBREG_REG expression. */ static int -reload_inner_reg_of_subreg (x, mode) +reload_inner_reg_of_subreg (x, mode, output) rtx x; enum machine_mode mode; + int output; { rtx inner; @@ -807,9 +834,10 @@ reload_inner_reg_of_subreg (x, mode) word and the number of regs for INNER is not the same as the number of words in INNER, then INNER will need reloading. */ return (GET_MODE_SIZE (mode) <= UNITS_PER_WORD + && output && GET_MODE_SIZE (GET_MODE (inner)) > UNITS_PER_WORD && ((GET_MODE_SIZE (GET_MODE (inner)) / UNITS_PER_WORD) - != HARD_REGNO_NREGS (REGNO (inner), GET_MODE (inner)))); + != (int) HARD_REGNO_NREGS (REGNO (inner), GET_MODE (inner)))); } /* Record one reload that needs to be performed. @@ -818,7 +846,7 @@ reload_inner_reg_of_subreg (x, mode) (IN is zero for data not read, and OUT is zero for data not written.) INLOC and OUTLOC point to the places in the instructions where IN and OUT were found. - If IN and OUT are both non-zero, it means the same register must be used + If IN and OUT are both nonzero, it means the same register must be used to reload both IN and OUT. CLASS is a register class required for the reloaded data. @@ -913,7 +941,7 @@ push_reload (in, out, inloc, outloc, class, default: break; - } + } /* If we are reloading a (SUBREG constant ...), really reload just the inside expression in its own mode. Similarly for (SUBREG (PLUS ...)). @@ -947,9 +975,8 @@ push_reload (in, out, inloc, outloc, class, if (in != 0 && GET_CODE (in) == SUBREG && (subreg_lowpart_p (in) || strict_low) -#ifdef CLASS_CANNOT_CHANGE_MODE - && (class != CLASS_CANNOT_CHANGE_MODE - || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)), inmode)) +#ifdef CANNOT_CHANGE_MODE_CLASS + && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)), inmode, class) #endif && (CONSTANT_P (SUBREG_REG (in)) || GET_CODE (SUBREG_REG (in)) == PLUS @@ -986,8 +1013,8 @@ push_reload (in, out, inloc, outloc, class, > UNITS_PER_WORD) && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) / UNITS_PER_WORD) - != HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)), - GET_MODE (SUBREG_REG (in))))) + != (int) HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)), + GET_MODE (SUBREG_REG (in))))) || ! HARD_REGNO_MODE_OK (subreg_regno (in), inmode))) #ifdef SECONDARY_INPUT_RELOAD_CLASS || (SECONDARY_INPUT_RELOAD_CLASS (class, inmode, in) != NO_REGS @@ -996,14 +1023,11 @@ push_reload (in, out, inloc, outloc, class, SUBREG_REG (in)) == NO_REGS)) #endif -#ifdef CLASS_CANNOT_CHANGE_MODE +#ifdef CANNOT_CHANGE_MODE_CLASS || (GET_CODE (SUBREG_REG (in)) == REG && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER - && (TEST_HARD_REG_BIT - (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], - REGNO (SUBREG_REG (in)))) - && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)), - inmode)) + && REG_CANNOT_CHANGE_MODE_P + (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)), inmode)) #endif )) { @@ -1030,7 +1054,7 @@ push_reload (in, out, inloc, outloc, class, /* Similar issue for (SUBREG constant ...) if it was not handled by the code above. This can happen if SUBREG_BYTE != 0. */ - if (in != 0 && reload_inner_reg_of_subreg (in, inmode)) + if (in != 0 && reload_inner_reg_of_subreg (in, inmode, 0)) { enum reg_class in_class = class; @@ -1040,14 +1064,15 @@ push_reload (in, out, inloc, outloc, class, subreg_regno_offset (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)), SUBREG_BYTE (in), - GET_MODE (in))); + GET_MODE (in)), + REGNO (SUBREG_REG (in))); /* This relies on the fact that emit_reload_insns outputs the instructions for input reloads of type RELOAD_OTHER in the same order as the reloads. Thus if the outer reload is also of type RELOAD_OTHER, we are guaranteed that this inner reload will be output before the outer reload. */ - push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), (rtx *)0, + push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), (rtx *) 0, in_class, VOIDmode, VOIDmode, 0, 0, opnum, type); dont_remove_subreg = 1; } @@ -1060,10 +1085,8 @@ push_reload (in, out, inloc, outloc, class, and in that case the constraint should label it input-output.) */ if (out != 0 && GET_CODE (out) == SUBREG && (subreg_lowpart_p (out) || strict_low) -#ifdef CLASS_CANNOT_CHANGE_MODE - && (class != CLASS_CANNOT_CHANGE_MODE - || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)), - outmode)) +#ifdef CANNOT_CHANGE_MODE_CLASS + && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)), outmode, class) #endif && (CONSTANT_P (SUBREG_REG (out)) || strict_low @@ -1087,8 +1110,8 @@ push_reload (in, out, inloc, outloc, class, > UNITS_PER_WORD) && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) / UNITS_PER_WORD) - != HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)), - GET_MODE (SUBREG_REG (out))))) + != (int) HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)), + GET_MODE (SUBREG_REG (out))))) || ! HARD_REGNO_MODE_OK (subreg_regno (out), outmode))) #ifdef SECONDARY_OUTPUT_RELOAD_CLASS || (SECONDARY_OUTPUT_RELOAD_CLASS (class, outmode, out) != NO_REGS @@ -1097,14 +1120,12 @@ push_reload (in, out, inloc, outloc, class, SUBREG_REG (out)) == NO_REGS)) #endif -#ifdef CLASS_CANNOT_CHANGE_MODE +#ifdef CANNOT_CHANGE_MODE_CLASS || (GET_CODE (SUBREG_REG (out)) == REG && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER - && (TEST_HARD_REG_BIT - (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], - REGNO (SUBREG_REG (out)))) - && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)), - outmode)) + && REG_CANNOT_CHANGE_MODE_P (REGNO (SUBREG_REG (out)), + GET_MODE (SUBREG_REG (out)), + outmode)) #endif )) { @@ -1126,7 +1147,7 @@ push_reload (in, out, inloc, outloc, class, However, we must reload the inner reg *as well as* the subreg in that case. In this case, the inner reg is an in-out reload. */ - if (out != 0 && reload_inner_reg_of_subreg (out, outmode)) + if (out != 0 && reload_inner_reg_of_subreg (out, outmode, 1)) { /* This relies on the fact that emit_reload_insns outputs the instructions for output reloads of type RELOAD_OTHER in reverse @@ -1140,7 +1161,8 @@ push_reload (in, out, inloc, outloc, class, subreg_regno_offset (REGNO (SUBREG_REG (out)), GET_MODE (SUBREG_REG (out)), SUBREG_BYTE (out), - GET_MODE (out))), + GET_MODE (out)), + REGNO (SUBREG_REG (out))), VOIDmode, VOIDmode, 0, 0, opnum, RELOAD_OTHER); } @@ -1265,9 +1287,9 @@ push_reload (in, out, inloc, outloc, class, #ifdef SECONDARY_MEMORY_NEEDED /* If a memory location is needed for the copy, make one. */ - if (in != 0 && GET_CODE (in) == REG - && REGNO (in) < FIRST_PSEUDO_REGISTER - && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)), + if (in != 0 && (GET_CODE (in) == REG || GET_CODE (in) == SUBREG) + && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER + && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)), class, inmode)) get_secondary_mem (in, inmode, opnum, type); #endif @@ -1295,9 +1317,10 @@ push_reload (in, out, inloc, outloc, class, n_reloads++; #ifdef SECONDARY_MEMORY_NEEDED - if (out != 0 && GET_CODE (out) == REG - && REGNO (out) < FIRST_PSEUDO_REGISTER - && SECONDARY_MEMORY_NEEDED (class, REGNO_REG_CLASS (REGNO (out)), + if (out != 0 && (GET_CODE (out) == REG || GET_CODE (out) == SUBREG) + && reg_or_subregno (out) < FIRST_PSEUDO_REGISTER + && SECONDARY_MEMORY_NEEDED (class, + REGNO_REG_CLASS (reg_or_subregno (out)), outmode)) get_secondary_mem (out, outmode, opnum, type); #endif @@ -1544,6 +1567,25 @@ push_replacement (loc, reloadnum, mode) r->mode = mode; } } + +/* Duplicate any replacement we have recorded to apply at + location ORIG_LOC to also be performed at DUP_LOC. + This is used in insn patterns that use match_dup. */ + +static void +dup_replacements (dup_loc, orig_loc) + rtx *dup_loc; + rtx *orig_loc; +{ + int i, n = n_replacements; + + for (i = 0; i < n; i++) + { + struct replacement *r = &replacements[i]; + if (r->where == orig_loc) + push_replacement (dup_loc, r->what, r->mode); + } +} /* Transfer all replacements that used to be in reload FROM to be in reload TO. */ @@ -1562,7 +1604,7 @@ transfer_replacements (to, from) /* IN_RTX is the value loaded by a reload that we now decided to inherit, or a subpart of it. If we have any replacements registered for IN_RTX, cancel the reloads that were supposed to load them. - Return non-zero if we canceled any reloads. */ + Return nonzero if we canceled any reloads. */ int remove_address_replacements (in_rtx) rtx in_rtx; @@ -1693,7 +1735,8 @@ combine_reloads () && ! (GET_CODE (rld[i].in) == REG && reg_overlap_mentioned_for_reload_p (rld[i].in, rld[output_reload].out)))) - && ! reload_inner_reg_of_subreg (rld[i].in, rld[i].inmode) + && ! reload_inner_reg_of_subreg (rld[i].in, rld[i].inmode, + rld[i].when_needed != RELOAD_FOR_INPUT) && (reg_class_size[(int) rld[i].class] || SMALL_REGISTER_CLASSES) /* We will allow making things slightly worse by combining an @@ -1801,7 +1844,7 @@ combine_reloads () If FOR_REAL is -1, this should not be done, because this call is just to see if a register can be found, not to find and install it. - EARLYCLOBBER is non-zero if OUT is an earlyclobber operand. This + EARLYCLOBBER is nonzero if OUT is an earlyclobber operand. This puts an additional constraint on being able to use IN for OUT since IN must not appear elsewhere in the insn (it is assumed that IN itself is safe from the earlyclobber). */ @@ -1879,6 +1922,7 @@ find_dummy_reload (real_in, real_out, inloc, outloc, *inloc = const0_rtx; if (regno < FIRST_PSEUDO_REGISTER + && HARD_REGNO_MODE_OK (regno, outmode) && ! refers_to_regno_for_reload_p (regno, regno + nwords, PATTERN (this_insn), outloc)) { @@ -1925,7 +1969,7 @@ find_dummy_reload (real_in, real_out, inloc, outloc, unsigned int regno = REGNO (in) + in_offset; unsigned int nwords = HARD_REGNO_NREGS (regno, inmode); - if (! refers_to_regno_for_reload_p (regno, regno + nwords, out, (rtx*)0) + if (! refers_to_regno_for_reload_p (regno, regno + nwords, out, (rtx*) 0) && ! hard_reg_set_here_p (regno, regno + nwords, PATTERN (this_insn)) && (! earlyclobber @@ -2103,13 +2147,13 @@ operands_match_p (x, y) /* If two operands must match, because they are really a single operand of an assembler insn, then two postincrements are invalid because the assembler insn would increment only once. - On the other hand, an postincrement matches ordinary indexing + On the other hand, a postincrement matches ordinary indexing if the postincrement is the output operand. */ if (code == POST_DEC || code == POST_INC || code == POST_MODIFY) return operands_match_p (XEXP (x, 0), y); /* Two preincrements are invalid because the assembler insn would increment only once. - On the other hand, an preincrement matches ordinary indexing + On the other hand, a preincrement matches ordinary indexing if the preincrement is the input operand. In this case, return 2, since some callers need to do special things when this happens. */ @@ -2344,7 +2388,7 @@ immune_p (x, y, ydata) struct decomposition xdata; if (ydata.reg_flag) - return !refers_to_regno_for_reload_p (ydata.start, ydata.end, x, (rtx*)0); + return !refers_to_regno_for_reload_p (ydata.start, ydata.end, x, (rtx*) 0); if (ydata.safe) return 1; @@ -2432,6 +2476,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) char pref_or_nothing[MAX_RECOG_OPERANDS]; /* Nonzero for a MEM operand whose entire address needs a reload. */ int address_reloaded[MAX_RECOG_OPERANDS]; + /* Nonzero for an address operand that needs to be completely reloaded. */ + int address_operand_reloaded[MAX_RECOG_OPERANDS]; /* Value of enum reload_type to use for operand. */ enum reload_type operand_type[MAX_RECOG_OPERANDS]; /* Value of enum reload_type to use within address of operand. */ @@ -2545,8 +2591,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) /* Scan this operand's constraint to see if it is an output operand, an in-out operand, is commutative, or should match another. */ - while ((c = *p++)) + while ((c = *p)) { + p += CONSTRAINT_LEN (c, p); if (c == '=') modified[i] = RELOAD_WRITE; else if (c == '+') @@ -2610,6 +2657,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) RTX_CODE code = GET_CODE (recog_data.operand[i]); address_reloaded[i] = 0; + address_operand_reloaded[i] = 0; operand_type[i] = (modified[i] == RELOAD_READ ? RELOAD_FOR_INPUT : modified[i] == RELOAD_WRITE ? RELOAD_FOR_OUTPUT : RELOAD_OTHER); @@ -2621,12 +2669,14 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) if (*constraints[i] == 0) /* Ignore things like match_operator operands. */ ; - else if (constraints[i][0] == 'p') + else if (constraints[i][0] == 'p' + || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i])) { - find_reloads_address (VOIDmode, (rtx*)0, - recog_data.operand[i], - recog_data.operand_loc[i], - i, operand_type[i], ind_levels, insn); + address_operand_reloaded[i] + = find_reloads_address (recog_data.operand_mode[i], (rtx*) 0, + recog_data.operand[i], + recog_data.operand_loc[i], + i, operand_type[i], ind_levels, insn); /* If we now have a simple operand where we used to have a PLUS or MULT, re-recognize and try again. */ @@ -2643,6 +2693,10 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) recog_data.operand[i] = *recog_data.operand_loc[i]; substed_operand[i] = recog_data.operand[i]; + + /* Address operands are reloaded in their existing mode, + no matter what is specified in the machine description. */ + operand_mode[i] = GET_MODE (recog_data.operand[i]); } else if (code == MEM) { @@ -2786,6 +2840,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) for (i = 0; i < noperands; i++) { char *p = constraints[i]; + char *end; + int len; int win = 0; int did_match = 0; /* 0 => this operand can be reloaded somehow for this alternative. */ @@ -2793,6 +2849,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) /* 0 => this operand can be reloaded if the alternative allows regs. */ int winreg = 0; int c; + int m; rtx operand = recog_data.operand[i]; int offset = 0; /* Nonzero means this is a MEM that must be reloaded into a reg @@ -2855,7 +2912,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) by forcing the reload. ??? When is it right at this stage to have a subreg - of a mem that is _not_ to be handled specialy? IMO + of a mem that is _not_ to be handled specially? IMO those should have been reduced to just a mem. */ || ((GET_CODE (operand) == MEM || (GET_CODE (operand)== REG @@ -2921,9 +2978,16 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) or set WINREG if this operand could fit after reloads provided the constraint allows some registers. */ - while (*p && (c = *p++) != ',') - switch (c) + do + switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c) { + case '\0': + len = 0; + break; + case ',': + c = '\0'; + break; + case '=': case '+': case '*': break; @@ -2944,15 +3008,19 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) case '#': /* Ignore rest of this alternative as far as reloading is concerned. */ - while (*p && *p != ',') + do p++; + while (*p && *p != ','); + len = 0; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - c = strtoul (p - 1, &p, 10); + m = strtoul (p, &end, 10); + p = end; + len = 0; - this_alternative_matches[i] = c; + this_alternative_matches[i] = m; /* We are supposed to match a previous operand. If we do, we win if that one did. If we do not, count both of the operands as losers. @@ -2960,7 +3028,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) only a single reload insn will be needed to make the two operands win. As a result, this alternative may be rejected when it is actually desirable.) */ - if ((swapped && (c != commutative || i != commutative + 1)) + if ((swapped && (m != commutative || i != commutative + 1)) /* If we are matching as if two operands were swapped, also pretend that operands_match had been computed with swapped. @@ -2968,22 +3036,22 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) don't exchange them, because operands_match is valid only on one side of its diagonal. */ ? (operands_match - [(c == commutative || c == commutative + 1) - ? 2 * commutative + 1 - c : c] + [(m == commutative || m == commutative + 1) + ? 2 * commutative + 1 - m : m] [(i == commutative || i == commutative + 1) ? 2 * commutative + 1 - i : i]) - : operands_match[c][i]) + : operands_match[m][i]) { /* If we are matching a non-offsettable address where an offsettable address was expected, then we must reject this combination, because we can't reload it. */ - if (this_alternative_offmemok[c] - && GET_CODE (recog_data.operand[c]) == MEM - && this_alternative[c] == (int) NO_REGS - && ! this_alternative_win[c]) + if (this_alternative_offmemok[m] + && GET_CODE (recog_data.operand[m]) == MEM + && this_alternative[m] == (int) NO_REGS + && ! this_alternative_win[m]) bad = 1; - did_match = this_alternative_win[c]; + did_match = this_alternative_win[m]; } else { @@ -2991,21 +3059,21 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) rtx value; /* Retroactively mark the operand we had to match as a loser, if it wasn't already. */ - if (this_alternative_win[c]) + if (this_alternative_win[m]) losers++; - this_alternative_win[c] = 0; - if (this_alternative[c] == (int) NO_REGS) + this_alternative_win[m] = 0; + if (this_alternative[m] == (int) NO_REGS) bad = 1; /* But count the pair only once in the total badness of this alternative, if the pair can be a dummy reload. */ value = find_dummy_reload (recog_data.operand[i], - recog_data.operand[c], + recog_data.operand[m], recog_data.operand_loc[i], - recog_data.operand_loc[c], - operand_mode[i], operand_mode[c], - this_alternative[c], -1, - this_alternative_earlyclobber[c]); + recog_data.operand_loc[m], + operand_mode[i], operand_mode[m], + this_alternative[m], -1, + this_alternative_earlyclobber[m]); if (value != 0) losers--; @@ -3013,7 +3081,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) /* This can be fixed with reloads if the operand we are supposed to match can be fixed with reloads. */ badop = 0; - this_alternative[i] = this_alternative[c]; + this_alternative[i] = this_alternative[m]; /* If we have to reload this operand and some previous operand also had to match the same thing as this @@ -3031,6 +3099,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) were handled in find_reloads_address. */ this_alternative[i] = (int) MODE_BASE_REG_CLASS (VOIDmode); win = 1; + badop = 0; break; case 'm': @@ -3120,27 +3189,18 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) break; case 'E': -#ifndef REAL_ARITHMETIC - /* Match any floating double constant, but only if - we can examine the bits of it reliably. */ - if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT - || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD) - && GET_MODE (operand) != VOIDmode && ! flag_pretend_float) - break; -#endif - if (GET_CODE (operand) == CONST_DOUBLE) - win = 1; - break; - case 'F': - if (GET_CODE (operand) == CONST_DOUBLE) + if (GET_CODE (operand) == CONST_DOUBLE + || (GET_CODE (operand) == CONST_VECTOR + && (GET_MODE_CLASS (GET_MODE (operand)) + == MODE_VECTOR_FLOAT))) win = 1; break; case 'G': case 'H': if (GET_CODE (operand) == CONST_DOUBLE - && CONST_DOUBLE_OK_FOR_LETTER_P (operand, c)) + && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (operand, c, p)) win = 1; break; @@ -3174,7 +3234,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) case 'O': case 'P': if (GET_CODE (operand) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (operand), c)) + && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operand), c, p)) win = 1; break; @@ -3207,17 +3267,62 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) goto reg; default: - if (REG_CLASS_FROM_LETTER (c) == NO_REGS) + if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS) { -#ifdef EXTRA_CONSTRAINT - if (EXTRA_CONSTRAINT (operand, c)) +#ifdef EXTRA_CONSTRAINT_STR + if (EXTRA_MEMORY_CONSTRAINT (c, p)) + { + if (force_reload) + break; + if (EXTRA_CONSTRAINT_STR (operand, c, p)) + win = 1; + /* If the address was already reloaded, + we win as well. */ + if (GET_CODE (operand) == MEM && address_reloaded[i]) + win = 1; + /* Likewise if the address will be reloaded because + reg_equiv_address is nonzero. For reg_equiv_mem + we have to check. */ + if (GET_CODE (operand) == REG + && REGNO (operand) >= FIRST_PSEUDO_REGISTER + && reg_renumber[REGNO (operand)] < 0 + && ((reg_equiv_mem[REGNO (operand)] != 0 + && EXTRA_CONSTRAINT_STR (reg_equiv_mem[REGNO (operand)], c, p)) + || (reg_equiv_address[REGNO (operand)] != 0))) + win = 1; + + /* If we didn't already win, we can reload + constants via force_const_mem, and other + MEMs by reloading the address like for 'o'. */ + if ((CONSTANT_P (operand) && GET_CODE (operand) != HIGH) + || GET_CODE (operand) == MEM) + badop = 0; + constmemok = 1; + offmemok = 1; + break; + } + if (EXTRA_ADDRESS_CONSTRAINT (c, p)) + { + if (EXTRA_CONSTRAINT_STR (operand, c, p)) + win = 1; + + /* If we didn't already win, we can reload + the address into a base register. */ + this_alternative[i] = (int) MODE_BASE_REG_CLASS (VOIDmode); + badop = 0; + break; + } + + if (EXTRA_CONSTRAINT_STR (operand, c, p)) win = 1; #endif break; } this_alternative[i] - = (int) reg_class_subunion[this_alternative[i]][(int) REG_CLASS_FROM_LETTER (c)]; + = (int) (reg_class_subunion + [this_alternative[i]] + [(int) REG_CLASS_FROM_CONSTRAINT (c, p)]); reg: if (GET_MODE (operand) == BLKmode) break; @@ -3228,6 +3333,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) win = 1; break; } + while ((p += len), c); constraints[i] = p; @@ -3572,7 +3678,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) for (i = 0; i < noperands; i++) goal_alternative_matched[i] = -1; - + for (i = 0; i < noperands; i++) if (! goal_alternative_win[i] && goal_alternative_matches[i] >= 0) @@ -3685,7 +3791,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) { operand_reloadnum[i] = push_reload (XEXP (recog_data.operand[i], 0), NULL_RTX, - &XEXP (recog_data.operand[i], 0), (rtx*)0, + &XEXP (recog_data.operand[i], 0), (rtx*) 0, MODE_BASE_REG_CLASS (VOIDmode), GET_MODE (XEXP (recog_data.operand[i], 0)), VOIDmode, 0, 0, i, RELOAD_FOR_INPUT); @@ -3776,6 +3882,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) } else if (goal_alternative_matched[i] < 0 && goal_alternative_matches[i] < 0 + && !address_operand_reloaded[i] && optimize) { /* For each non-matching operand that's a MEM or a pseudo-register @@ -3923,9 +4030,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) { int opno = recog_data.dup_num[i]; *recog_data.dup_loc[i] = *recog_data.operand_loc[opno]; - if (operand_reloadnum[opno] >= 0) - push_replacement (recog_data.dup_loc[i], operand_reloadnum[opno], - insn_data[insn_code_number].operand[opno].mode); + dup_replacements (recog_data.dup_loc[i], recog_data.operand_loc[opno]); } #if 0 @@ -4241,6 +4346,23 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) rld[i].nregs = CLASS_MAX_NREGS (rld[i].class, rld[i].mode); } + /* Special case a simple move with an input reload and a + destination of a hard reg, if the hard reg is ok, use it. */ + for (i = 0; i < n_reloads; i++) + if (rld[i].when_needed == RELOAD_FOR_INPUT + && GET_CODE (PATTERN (insn)) == SET + && GET_CODE (SET_DEST (PATTERN (insn))) == REG + && SET_SRC (PATTERN (insn)) == rld[i].in) + { + rtx dest = SET_DEST (PATTERN (insn)); + unsigned int regno = REGNO (dest); + + if (regno < FIRST_PSEUDO_REGISTER + && TEST_HARD_REG_BIT (reg_class_contents[rld[i].class], regno) + && HARD_REGNO_MODE_OK (regno, rld[i].mode)) + rld[i].reg_rtx = dest; + } + return retval; } @@ -4261,8 +4383,9 @@ alternative_allows_memconst (constraint, altnum) } /* Scan the requested alternative for 'm' or 'o'. If one of them is present, this alternative accepts memory constants. */ - while ((c = *constraint++) && c != ',' && c != '#') - if (c == 'm' || c == 'o') + for (; (c = *constraint) && c != ',' && c != '#'; + constraint += CONSTRAINT_LEN (c, constraint)) + if (c == 'm' || c == 'o' || EXTRA_MEMORY_CONSTRAINT (c, constraint)) return 1; return 0; } @@ -4376,53 +4499,17 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn, reg_equiv_constant[regno])) != 0) return tem; - if (GET_MODE_BITSIZE (GET_MODE (x)) == BITS_PER_WORD - && regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0 - && reg_equiv_constant[regno] != 0 - && (tem = operand_subword (reg_equiv_constant[regno], - SUBREG_BYTE (x) / UNITS_PER_WORD, 0, - GET_MODE (SUBREG_REG (x)))) != 0) + if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0 + && reg_equiv_constant[regno] != 0) { - /* TEM is now a word sized constant for the bits from X that - we wanted. However, TEM may be the wrong representation. - - Use gen_lowpart_common to convert a CONST_INT into a - CONST_DOUBLE and vice versa as needed according to by the mode - of the SUBREG. */ - tem = gen_lowpart_common (GET_MODE (x), tem); + tem = + simplify_gen_subreg (GET_MODE (x), reg_equiv_constant[regno], + GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x)); if (!tem) abort (); return tem; } - /* If the SUBREG is wider than a word, the above test will fail. - For example, we might have a SImode SUBREG of a DImode SUBREG_REG - for a 16 bit target, or a DImode SUBREG of a TImode SUBREG_REG for - a 32 bit target. We still can - and have to - handle this - for non-paradoxical subregs of CONST_INTs. */ - if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0 - && reg_equiv_constant[regno] != 0 - && GET_CODE (reg_equiv_constant[regno]) == CONST_INT - && (GET_MODE_SIZE (GET_MODE (x)) - < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) - { - int shift = SUBREG_BYTE (x) * BITS_PER_UNIT; - if (WORDS_BIG_ENDIAN) - shift = (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - - GET_MODE_BITSIZE (GET_MODE (x)) - - shift); - /* Here we use the knowledge that CONST_INTs have a - HOST_WIDE_INT field. */ - if (shift >= HOST_BITS_PER_WIDE_INT) - shift = HOST_BITS_PER_WIDE_INT - 1; - return GEN_INT (INTVAL (reg_equiv_constant[regno]) >> shift); - } - - if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0 - && reg_equiv_constant[regno] != 0 - && GET_MODE (reg_equiv_constant[regno]) == VOIDmode) - abort (); - /* If the subreg contains a reg that will be converted to a mem, convert the subreg to a narrower memref now. Otherwise, we would get (subreg (mem ...) ...), @@ -4502,6 +4589,27 @@ make_memloc (ad, regno) return tem; } +/* Returns true if AD could be turned into a valid memory reference + to mode MODE by reloading the part pointed to by PART into a + register. */ + +static int +maybe_memory_address_p (mode, ad, part) + enum machine_mode mode; + rtx ad; + rtx *part; +{ + int retv; + rtx tem = *part; + rtx reg = gen_rtx_REG (GET_MODE (tem), max_reg_num ()); + + *part = reg; + retv = memory_address_p (mode, ad); + *part = tem; + + return retv; +} + /* Record all reloads needed for handling memory address AD which appears in *LOC in a memory reference to mode MODE which itself is found in location *MEMREFLOC. @@ -4568,9 +4676,9 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn) tem = make_memloc (ad, regno); if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0))) { - find_reloads_address (GET_MODE (tem), (rtx*)0, XEXP (tem, 0), - &XEXP (tem, 0), opnum, ADDR_TYPE (type), - ind_levels, insn); + find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0), + &XEXP (tem, 0), opnum, + ADDR_TYPE (type), ind_levels, insn); } /* We can avoid a reload if the register's equivalent memory expression is valid as an indirect memory address. @@ -4617,7 +4725,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn) return 0; /* If we do not have one of the cases above, we must do the reload. */ - push_reload (ad, NULL_RTX, loc, (rtx*)0, MODE_BASE_REG_CLASS (mode), + push_reload (ad, NULL_RTX, loc, (rtx*) 0, MODE_BASE_REG_CLASS (mode), GET_MODE (ad), VOIDmode, 0, 0, opnum, type); return 1; } @@ -4717,7 +4825,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn) { /* Must use TEM here, not AD, since it is the one that will have any subexpressions reloaded, if needed. */ - push_reload (tem, NULL_RTX, loc, (rtx*)0, + push_reload (tem, NULL_RTX, loc, (rtx*) 0, MODE_BASE_REG_CLASS (mode), GET_MODE (tem), VOIDmode, 0, 0, opnum, type); @@ -4801,7 +4909,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn) || XEXP (XEXP (ad, 0), 0) == arg_pointer_rtx #endif || XEXP (XEXP (ad, 0), 0) == stack_pointer_rtx) - && ! memory_address_p (mode, ad)) + && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 1))) { *loc = ad = gen_rtx_PLUS (GET_MODE (ad), plus_constant (XEXP (XEXP (ad, 0), 0), @@ -4826,7 +4934,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn) || XEXP (XEXP (ad, 0), 1) == arg_pointer_rtx #endif || XEXP (XEXP (ad, 0), 1) == stack_pointer_rtx) - && ! memory_address_p (mode, ad)) + && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 0))) { *loc = ad = gen_rtx_PLUS (GET_MODE (ad), XEXP (XEXP (ad, 0), 0), @@ -4909,6 +5017,7 @@ subst_reg_equivs (ad, insn) case CONST_INT: case CONST: case CONST_DOUBLE: + case CONST_VECTOR: case SYMBOL_REF: case LABEL_REF: case PC: @@ -5090,7 +5199,7 @@ update_auto_inc_notes (insn, regno, reloadnum) for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) if (REG_NOTE_KIND (link) == REG_INC - && REGNO (XEXP (link, 0)) == regno) + && (int) REGNO (XEXP (link, 0)) == regno) push_replacement (&XEXP (link, 0), reloadnum, VOIDmode); #endif } @@ -5297,7 +5406,7 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) We can't use ADDR_TYPE (type) here, because we need to write back the value after reading it, hence we actually need two registers. */ - find_reloads_address (GET_MODE (tem), 0, XEXP (tem, 0), + find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0), &XEXP (tem, 0), opnum, RELOAD_OTHER, ind_levels, insn); @@ -5432,7 +5541,7 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) else { reloadnum - = push_reload (x, NULL_RTX, loc, (rtx*)0, + = push_reload (x, NULL_RTX, loc, (rtx*) 0, (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)), GET_MODE (x), GET_MODE (x), 0, 0, @@ -5473,7 +5582,7 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) XEXP (XEXP (x, 0), 0), &XEXP (XEXP (x, 0), 0), opnum, type, ind_levels, insn); - reloadnum = push_reload (x, NULL_RTX, loc, (rtx*)0, + reloadnum = push_reload (x, NULL_RTX, loc, (rtx*) 0, (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)), GET_MODE (x), VOIDmode, 0, 0, opnum, type); @@ -5503,7 +5612,7 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0), opnum, ADDR_TYPE (type), ind_levels, insn); - push_reload (*loc, NULL_RTX, loc, (rtx*)0, + push_reload (*loc, NULL_RTX, loc, (rtx*) 0, (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)), GET_MODE (x), VOIDmode, 0, 0, opnum, type); return 1; @@ -5525,7 +5634,7 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) that feeds this insn. */ if (reg_equiv_mem[regno] != 0) { - push_reload (reg_equiv_mem[regno], NULL_RTX, loc, (rtx*)0, + push_reload (reg_equiv_mem[regno], NULL_RTX, loc, (rtx*) 0, (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)), GET_MODE (x), VOIDmode, 0, 0, opnum, type); @@ -5554,7 +5663,7 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) || !(context ? REGNO_OK_FOR_INDEX_P (regno) : REGNO_MODE_OK_FOR_BASE_P (regno, mode)))) { - push_reload (x, NULL_RTX, loc, (rtx*)0, + push_reload (x, NULL_RTX, loc, (rtx*) 0, (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)), GET_MODE (x), VOIDmode, 0, 0, opnum, type); return 1; @@ -5566,7 +5675,7 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) from before this insn to after it. */ if (regno_clobbered_p (regno, this_insn, GET_MODE (x), 0)) { - push_reload (x, NULL_RTX, loc, (rtx*)0, + push_reload (x, NULL_RTX, loc, (rtx*) 0, (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)), GET_MODE (x), VOIDmode, 0, 0, opnum, type); return 1; @@ -5582,12 +5691,12 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) needless copies if SUBREG_REG is multi-word. */ if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER) { - int regno = subreg_regno (x); + int regno ATTRIBUTE_UNUSED = subreg_regno (x); if (! (context ? REGNO_OK_FOR_INDEX_P (regno) : REGNO_MODE_OK_FOR_BASE_P (regno, mode))) { - push_reload (x, NULL_RTX, loc, (rtx*)0, + push_reload (x, NULL_RTX, loc, (rtx*) 0, (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)), GET_MODE (x), VOIDmode, 0, 0, opnum, type); @@ -5600,12 +5709,12 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) { enum reg_class class = (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)); - if (CLASS_MAX_NREGS (class, GET_MODE (SUBREG_REG (x))) + if ((unsigned) CLASS_MAX_NREGS (class, GET_MODE (SUBREG_REG (x))) > reg_class_size[class]) { x = find_reloads_subreg_address (x, 0, opnum, type, ind_levels, insn); - push_reload (x, NULL_RTX, loc, (rtx*)0, class, + push_reload (x, NULL_RTX, loc, (rtx*) 0, class, GET_MODE (x), VOIDmode, 0, 0, opnum, type); return 1; } @@ -5681,7 +5790,7 @@ find_reloads_address_part (x, loc, class, mode, opnum, type, ind_levels) opnum, type, ind_levels, 0); } - push_reload (x, NULL_RTX, loc, (rtx*)0, class, + push_reload (x, NULL_RTX, loc, (rtx*) 0, class, mode, VOIDmode, 0, 0, opnum, type); } @@ -5881,49 +5990,70 @@ subst_reloads (insn) } } -/* Make a copy of any replacements being done into X and move those copies - to locations in Y, a copy of X. We only look at the highest level of - the RTL. */ +/* Make a copy of any replacements being done into X and move those + copies to locations in Y, a copy of X. */ void copy_replacements (x, y) - rtx x; - rtx y; + rtx x, y; { - int i, j; - enum rtx_code code = GET_CODE (x); - const char *fmt = GET_RTX_FORMAT (code); - struct replacement *r; - /* We can't support X being a SUBREG because we might then need to know its location if something inside it was replaced. */ - if (code == SUBREG) + if (GET_CODE (x) == SUBREG) abort (); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - if (fmt[i] == 'e') - for (j = 0; j < n_replacements; j++) + copy_replacements_1 (&x, &y, n_replacements); +} + +static void +copy_replacements_1 (px, py, orig_replacements) + rtx *px; + rtx *py; + int orig_replacements; +{ + int i, j; + rtx x, y; + struct replacement *r; + enum rtx_code code; + const char *fmt; + + for (j = 0; j < orig_replacements; j++) + { + if (replacements[j].subreg_loc == px) { - if (replacements[j].subreg_loc == &XEXP (x, i)) - { - r = &replacements[n_replacements++]; - r->where = replacements[j].where; - r->subreg_loc = &XEXP (y, i); - r->what = replacements[j].what; - r->mode = replacements[j].mode; - } - else if (replacements[j].where == &XEXP (x, i)) - { - r = &replacements[n_replacements++]; - r->where = &XEXP (y, i); - r->subreg_loc = 0; - r->what = replacements[j].what; - r->mode = replacements[j].mode; - } + r = &replacements[n_replacements++]; + r->where = replacements[j].where; + r->subreg_loc = py; + r->what = replacements[j].what; + r->mode = replacements[j].mode; } + else if (replacements[j].where == px) + { + r = &replacements[n_replacements++]; + r->where = py; + r->subreg_loc = 0; + r->what = replacements[j].what; + r->mode = replacements[j].mode; + } + } + + x = *px; + y = *py; + code = GET_CODE (x); + fmt = GET_RTX_FORMAT (code); + + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + copy_replacements_1 (&XEXP (x, i), &XEXP (y, i), orig_replacements); + else if (fmt[i] == 'E') + for (j = XVECLEN (x, i); --j >= 0; ) + copy_replacements_1 (&XVECEXP (x, i, j), &XVECEXP (y, i, j), + orig_replacements); + } } -/* Change any replacements being done to *X to be done to *Y */ +/* Change any replacements being done to *X to be done to *Y. */ void move_replacements (x, y) @@ -6045,7 +6175,7 @@ refers_to_regno_for_reload_p (regno, endregno, x, loc) if (reg_equiv_memory_loc[r]) return refers_to_regno_for_reload_p (regno, endregno, reg_equiv_memory_loc[r], - (rtx*)0); + (rtx*) 0); if (reg_equiv_constant[r]) return 0; @@ -6149,7 +6279,8 @@ reg_overlap_mentioned_for_reload_p (x, in) int regno, endregno; /* Overly conservative. */ - if (GET_CODE (x) == STRICT_LOW_PART) + if (GET_CODE (x) == STRICT_LOW_PART + || GET_RTX_CLASS (GET_CODE (x)) == 'a') x = XEXP (x, 0); /* If either argument is a constant, then modifying X can not affect IN. */ @@ -6185,13 +6316,16 @@ reg_overlap_mentioned_for_reload_p (x, in) else if (GET_CODE (x) == SCRATCH || GET_CODE (x) == PC || GET_CODE (x) == CC0) return reg_mentioned_p (x, in); + else if (GET_CODE (x) == PLUS) + return (reg_overlap_mentioned_for_reload_p (XEXP (x, 0), in) + || reg_overlap_mentioned_for_reload_p (XEXP (x, 1), in)); else abort (); endregno = regno + (regno < FIRST_PSEUDO_REGISTER ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1); - return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*)0); + return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0); } /* Return nonzero if anything in X contains a MEM. Look also for pseudo @@ -6446,7 +6580,7 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode) && refers_to_regno_for_reload_p (valueno, (valueno + HARD_REGNO_NREGS (valueno, mode)), - goal, (rtx*)0)) + goal, (rtx*) 0)) return 0; /* Reject registers that overlap GOAL. */ @@ -6790,7 +6924,7 @@ regno_clobbered_p (regno, insn, mode, sets) && GET_CODE (XEXP (elt, 0)) == REG) { unsigned int test = REGNO (XEXP (elt, 0)); - + if (test >= regno && test < endregno) return 1; }