[backport r180526 from gcc-4.7/trunk, PR46603 fix part 2 of 3 ] From: Eric Botcazou Subject: Re: PR rtl-optimization/46603 Date: Wed, 26 Oct 2011 15:50:13 +0200 List-Archive: > Thanks! You're welcome. I have also installed the attached patch which makes minor tweaks and fixes various issues in comments which have bugged me for years, the most glaring one being: Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where either M1 is not valid for R or M2 is wider than a word but we only need one word to store an M2-sized quantity in R. which seems to be hinting at some relativistic effect on the size of M2... No functional changes, tested on i586-suse-linux, applied on the mainline. gcc/ 2011-10-26 Eric Botcazou * reload.c (reload_inner_reg_of_subreg): Change type of return value and type of OUTPUT parameter to bool and adjust. Document MODE and OUTPUT parameters. Use HARD_REGISTER_P. Reorder final condition and improve associated comment. (push_reload): Clarify and update comments about reloading of subregs. Adjust calls to reload_inner_reg_of_subreg. Compute the class upfront for the reloading of subregs in the out case as well. --- gcc-4.6.2/gcc/reload.c.~1~ 2011-11-05 13:11:37.000000000 +0100 +++ gcc-4.6.2/gcc/reload.c 2011-11-05 13:14:59.000000000 +0100 @@ -256,7 +256,6 @@ static int push_secondary_reload (int, r enum insn_code *, secondary_reload_info *); static enum reg_class find_valid_class (enum machine_mode, enum machine_mode, int, unsigned int); -static int reload_inner_reg_of_subreg (rtx, enum machine_mode, int); static void push_replacement (rtx *, int, enum machine_mode); static void dup_replacements (rtx *, rtx *); static void combine_reloads (void); @@ -793,39 +792,39 @@ find_reusable_reload (rtx *p_in, rtx out return n_reloads; } -/* Return nonzero if X is a SUBREG which will require reloading of its - SUBREG_REG expression. */ +/* Return true if X is a SUBREG that will need reloading of its SUBREG_REG + expression. MODE is the mode that X will be used in. OUTPUT is true if + the function is invoked for the output part of an enclosing reload. */ -static int -reload_inner_reg_of_subreg (rtx x, enum machine_mode mode, int output) +static bool +reload_inner_reg_of_subreg (rtx x, enum machine_mode mode, bool output) { rtx inner; /* Only SUBREGs are problematical. */ if (GET_CODE (x) != SUBREG) - return 0; + return false; inner = SUBREG_REG (x); - /* If INNER is a constant or PLUS, then INNER must be reloaded. */ + /* If INNER is a constant or PLUS, then INNER will need reloading. */ if (CONSTANT_P (inner) || GET_CODE (inner) == PLUS) - return 1; + return true; - /* If INNER is not a hard register, then INNER will not need to - be reloaded. */ - if (!REG_P (inner) - || REGNO (inner) >= FIRST_PSEUDO_REGISTER) - return 0; + /* If INNER is not a hard register, then INNER will not need reloading. */ + if (!(REG_P (inner) && HARD_REGISTER_P (inner))) + return false; /* If INNER is not ok for MODE, then INNER will need reloading. */ - if (! HARD_REGNO_MODE_OK (subreg_regno (x), mode)) - return 1; + if (!HARD_REGNO_MODE_OK (subreg_regno (x), mode)) + return true; - /* If the outer part is a word or smaller, INNER larger than a - 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 + /* If this is for an output, and the outer part is a word or smaller, + INNER is larger than a word and the number of registers in INNER is + not the same as the number of words in INNER, then INNER will need + reloading (with an in-out reload). */ + return (output + && GET_MODE_SIZE (mode) <= UNITS_PER_WORD && GET_MODE_SIZE (GET_MODE (inner)) > UNITS_PER_WORD && ((GET_MODE_SIZE (GET_MODE (inner)) / UNITS_PER_WORD) != (int) hard_regno_nregs[REGNO (inner)][GET_MODE (inner)])); @@ -990,9 +989,9 @@ push_reload (rtx in, rtx out, rtx *inloc For machines that extend byte loads, do this for any SUBREG of a pseudo where both M1 and M2 are a word or smaller, M1 is wider than M2, and M2 is an integral mode that gets extended when loaded. - Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where - either M1 is not valid for R or M2 is wider than a word but we only - need one word to store an M2-sized quantity in R. + Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R + where either M1 is not valid for R or M2 is wider than a word but we + only need one register to store an M2-sized quantity in R. (However, if OUT is nonzero, we need to reload the reg *and* the subreg, so do nothing here, and let following statement handle it.) @@ -1079,17 +1078,16 @@ push_reload (rtx in, rtx out, rtx *inloc inmode = GET_MODE (in); } - /* Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where - either M1 is not valid for R or M2 is wider than a word but we only - need one word to store an M2-sized quantity in R. + /* Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R + where M1 is not valid for R if it was not handled by the code above. + + Similar issue for (SUBREG constant ...) if it was not handled by the + code above. This can happen if SUBREG_BYTE != 0. However, we must reload the inner reg *as well as* the subreg in that case. */ - /* 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, 0)) + if (in != 0 && reload_inner_reg_of_subreg (in, inmode, false)) { enum reg_class in_class = rclass; @@ -1162,31 +1160,32 @@ push_reload (rtx in, rtx out, rtx *inloc outmode = GET_MODE (out); } - /* Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where - either M1 is not valid for R or M2 is wider than a word but we only - need one word to store an M2-sized quantity in R. + /* Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R + where either M1 is not valid for R or M2 is wider than a word but we + only need one register to store an M2-sized quantity in R. 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. */ + that case and the inner reg is an in-out reload. */ - if (out != 0 && reload_inner_reg_of_subreg (out, outmode, 1)) + if (out != 0 && reload_inner_reg_of_subreg (out, outmode, true)) { + enum reg_class in_out_class + = find_valid_class (outmode, GET_MODE (SUBREG_REG (out)), + subreg_regno_offset (REGNO (SUBREG_REG (out)), + GET_MODE (SUBREG_REG (out)), + SUBREG_BYTE (out), + GET_MODE (out)), + REGNO (SUBREG_REG (out))); + /* This relies on the fact that emit_reload_insns outputs the instructions for output reloads of type RELOAD_OTHER in reverse order of the reloads. Thus if the outer reload is also of type RELOAD_OTHER, we are guaranteed that this inner reload will be output after the outer reload. */ - dont_remove_subreg = 1; push_reload (SUBREG_REG (out), SUBREG_REG (out), &SUBREG_REG (out), - &SUBREG_REG (out), - find_valid_class (outmode, GET_MODE (SUBREG_REG (out)), - subreg_regno_offset (REGNO (SUBREG_REG (out)), - GET_MODE (SUBREG_REG (out)), - SUBREG_BYTE (out), - GET_MODE (out)), - REGNO (SUBREG_REG (out))), - VOIDmode, VOIDmode, 0, 0, - opnum, RELOAD_OTHER); + &SUBREG_REG (out), in_out_class, VOIDmode, VOIDmode, + 0, 0, opnum, RELOAD_OTHER); + dont_remove_subreg = 1; } /* If IN appears in OUT, we can't share any input-only reload for IN. */