diff options
Diffstat (limited to 'gcc/reload.c')
-rw-r--r-- | gcc/reload.c | 165 |
1 files changed, 119 insertions, 46 deletions
diff --git a/gcc/reload.c b/gcc/reload.c index 9849aed..ea5bea6 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -791,7 +791,7 @@ reload_inner_reg_of_subreg (x, mode) return 0; /* If INNER is not ok for MODE, then INNER will need reloading. */ - if (! HARD_REGNO_MODE_OK (REGNO (inner) + SUBREG_WORD (x), mode)) + if (! HARD_REGNO_MODE_OK (subreg_regno (x), mode)) return 1; /* If the outer part is a word or smaller, INNER larger than a @@ -938,13 +938,12 @@ push_reload (in, out, inloc, outloc, class, Finally, reload the inner expression if it is a register that is in the class whose registers cannot be referenced in a different size - and M1 is not the same size as M2. If SUBREG_WORD is nonzero, we + and M1 is not the same size as M2. If SUBREG_BYTE is nonzero, we cannot reload just the inside since we might end up with the wrong register class. But if it is inside a STRICT_LOW_PART, we have no choice, so we hope we do get the right register class there. */ if (in != 0 && GET_CODE (in) == SUBREG - && (SUBREG_WORD (in) == 0 || strict_low) #ifdef CLASS_CANNOT_CHANGE_MODE && (class != CLASS_CANNOT_CHANGE_MODE || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)), inmode)) @@ -978,7 +977,7 @@ push_reload (in, out, inloc, outloc, class, && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER /* The case where out is nonzero is handled differently in the following statement. */ - && (out == 0 || SUBREG_WORD (in) == 0) + && (out == 0 || SUBREG_BYTE (in) == 0) && ((GET_MODE_SIZE (inmode) <= UNITS_PER_WORD && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) > UNITS_PER_WORD) @@ -986,9 +985,7 @@ push_reload (in, out, inloc, outloc, class, / UNITS_PER_WORD) != HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in))))) - || ! HARD_REGNO_MODE_OK ((REGNO (SUBREG_REG (in)) - + SUBREG_WORD (in)), - inmode))) + || ! HARD_REGNO_MODE_OK (subreg_regno (in), inmode))) #ifdef SECONDARY_INPUT_RELOAD_CLASS || (SECONDARY_INPUT_RELOAD_CLASS (class, inmode, in) != NO_REGS && (SECONDARY_INPUT_RELOAD_CLASS (class, @@ -1028,7 +1025,7 @@ push_reload (in, out, inloc, outloc, class, that case. */ /* Similar issue for (SUBREG constant ...) if it was not handled by the - code above. This can happen if SUBREG_WORD != 0. */ + code above. This can happen if SUBREG_BYTE != 0. */ if (in != 0 && reload_inner_reg_of_subreg (in, inmode)) { @@ -1038,7 +1035,11 @@ push_reload (in, out, inloc, outloc, class, 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), NULL_PTR, - find_valid_class (inmode, SUBREG_WORD (in)), + find_valid_class (inmode, + subreg_regno_offset (REGNO (SUBREG_REG (in)), + GET_MODE (SUBREG_REG (in)), + SUBREG_BYTE (in), + GET_MODE (in))), VOIDmode, VOIDmode, 0, 0, opnum, type); dont_remove_subreg = 1; } @@ -1050,7 +1051,7 @@ push_reload (in, out, inloc, outloc, class, (except in the case of STRICT_LOW_PART, and in that case the constraint should label it input-output.) */ if (out != 0 && GET_CODE (out) == SUBREG - && (SUBREG_WORD (out) == 0 || strict_low) + && (SUBREG_BYTE (out) == 0 || strict_low) #ifdef CLASS_CANNOT_CHANGE_MODE && (class != CLASS_CANNOT_CHANGE_MODE || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)), @@ -1080,9 +1081,7 @@ push_reload (in, out, inloc, outloc, class, / UNITS_PER_WORD) != HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)), GET_MODE (SUBREG_REG (out))))) - || ! HARD_REGNO_MODE_OK ((REGNO (SUBREG_REG (out)) - + SUBREG_WORD (out)), - outmode))) + || ! HARD_REGNO_MODE_OK (subreg_regno (out), outmode))) #ifdef SECONDARY_OUTPUT_RELOAD_CLASS || (SECONDARY_OUTPUT_RELOAD_CLASS (class, outmode, out) != NO_REGS && (SECONDARY_OUTPUT_RELOAD_CLASS (class, @@ -1129,7 +1128,11 @@ push_reload (in, out, inloc, outloc, class, dont_remove_subreg = 1; push_reload (SUBREG_REG (out), SUBREG_REG (out), &SUBREG_REG (out), &SUBREG_REG (out), - find_valid_class (outmode, SUBREG_WORD (out)), + find_valid_class (outmode, + subreg_regno_offset (REGNO (SUBREG_REG (out)), + GET_MODE (SUBREG_REG (out)), + SUBREG_BYTE (out), + GET_MODE (out))), VOIDmode, VOIDmode, 0, 0, opnum, RELOAD_OTHER); } @@ -1146,16 +1149,14 @@ push_reload (in, out, inloc, outloc, class, if (in != 0 && GET_CODE (in) == SUBREG && GET_CODE (SUBREG_REG (in)) == REG && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER && ! dont_remove_subreg) - in = gen_rtx_REG (GET_MODE (in), - REGNO (SUBREG_REG (in)) + SUBREG_WORD (in)); + in = gen_rtx_REG (GET_MODE (in), subreg_regno (in)); /* Similarly for OUT. */ if (out != 0 && GET_CODE (out) == SUBREG && GET_CODE (SUBREG_REG (out)) == REG && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER && ! dont_remove_subreg) - out = gen_rtx_REG (GET_MODE (out), - REGNO (SUBREG_REG (out)) + SUBREG_WORD (out)); + out = gen_rtx_REG (GET_MODE (out), subreg_regno (out)); /* Narrow down the class of register wanted if that is desirable on this machine for efficiency. */ @@ -1810,15 +1811,28 @@ find_dummy_reload (real_in, real_out, inloc, outloc, || GET_MODE_SIZE (inmode) > UNITS_PER_WORD)) return 0; + /* Note that {in,out}_offset are needed only when 'in' or 'out' + respectively refers to a hard register. */ + /* Find the inside of any subregs. */ while (GET_CODE (out) == SUBREG) { - out_offset = SUBREG_WORD (out); + if (GET_CODE (SUBREG_REG (out)) == REG + && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER) + out_offset += subreg_regno_offset (REGNO (SUBREG_REG (out)), + GET_MODE (SUBREG_REG (out)), + SUBREG_BYTE (out), + GET_MODE (out)); out = SUBREG_REG (out); } while (GET_CODE (in) == SUBREG) { - in_offset = SUBREG_WORD (in); + if (GET_CODE (SUBREG_REG (in)) == REG + && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER) + in_offset += subreg_regno_offset (REGNO (SUBREG_REG (in)), + GET_MODE (SUBREG_REG (in)), + SUBREG_BYTE (in), + GET_MODE (in)); in = SUBREG_REG (in); } @@ -2035,7 +2049,10 @@ operands_match_p (x, y) i = REGNO (SUBREG_REG (x)); if (i >= FIRST_PSEUDO_REGISTER) goto slow; - i += SUBREG_WORD (x); + i += subreg_regno_offset (REGNO (SUBREG_REG (x)), + GET_MODE (SUBREG_REG (x)), + SUBREG_BYTE (x), + GET_MODE (x)); } else i = REGNO (x); @@ -2045,7 +2062,10 @@ operands_match_p (x, y) j = REGNO (SUBREG_REG (y)); if (j >= FIRST_PSEUDO_REGISTER) goto slow; - j += SUBREG_WORD (y); + j += subreg_regno_offset (REGNO (SUBREG_REG (y)), + GET_MODE (SUBREG_REG (y)), + SUBREG_BYTE (y), + GET_MODE (y)); } else j = REGNO (y); @@ -2777,7 +2797,18 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) while (GET_CODE (operand) == SUBREG) { - offset += SUBREG_WORD (operand); + /* Offset only matters when operand is a REG and + it is a hard reg. This is because it is passed + to reg_fits_class_p if it is a REG and all pseudos + return 0 from that function. */ + if (GET_CODE (SUBREG_REG (operand)) == REG + && REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER) + { + offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)), + GET_MODE (SUBREG_REG (operand)), + SUBREG_BYTE (operand), + GET_MODE (operand)); + } operand = SUBREG_REG (operand); /* Force reload if this is a constant or PLUS or if there may be a problem accessing OPERAND in the outer mode. */ @@ -2828,6 +2859,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) ) #endif ) + /* This following hunk of code should no longer be + needed at all with SUBREG_BYTE. If you need this + code back, please explain to me why so I can + fix the real problem. -DaveM */ +#if 0 /* Subreg of a hard reg which can't handle the subreg's mode or which would handle that mode in the wrong number of registers for subregging to work. */ @@ -2841,7 +2877,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) != HARD_REGNO_NREGS (REGNO (operand), GET_MODE (operand)))) || ! HARD_REGNO_MODE_OK (REGNO (operand) + offset, - operand_mode[i])))) + operand_mode[i]))) +#endif + ) force_reload = 1; } @@ -3716,7 +3754,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) rtx operand = recog_data.operand[i]; while (GET_CODE (operand) == SUBREG) - operand = XEXP (operand, 0); + operand = SUBREG_REG (operand); if ((GET_CODE (operand) == MEM || (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER)) @@ -3766,7 +3804,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) operand = *recog_data.operand_loc[i]; while (GET_CODE (operand) == SUBREG) - operand = XEXP (operand, 0); + operand = SUBREG_REG (operand); if (GET_CODE (operand) == REG) { if (modified[i] != RELOAD_WRITE) @@ -3789,7 +3827,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) rtx operand = recog_data.operand[i]; while (GET_CODE (operand) == SUBREG) - operand = XEXP (operand, 0); + operand = SUBREG_REG (operand); if ((GET_CODE (operand) == MEM || (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER)) @@ -4303,7 +4341,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn, && regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0 && reg_equiv_constant[regno] != 0 && (tem = operand_subword (reg_equiv_constant[regno], - SUBREG_WORD (x), 0, + SUBREG_BYTE (x) / UNITS_PER_WORD, 0, GET_MODE (SUBREG_REG (x)))) != 0) { /* TEM is now a word sized constant for the bits from X that @@ -4329,7 +4367,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn, && (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) { - int shift = SUBREG_WORD (x) * BITS_PER_WORD; + 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)) @@ -4383,13 +4421,18 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn, the meaning of the memory access. */ enum machine_mode subreg_mode = GET_MODE (SUBREG_REG (x)); + /* SUBREG_REG (x) is a MEM, so we cant take the offset, instead we + calculate the register number as : + SUBREG_BYTE (x) / GET_MODE_SIZE (subreg_mode) */ if (is_set_dest) push_reload (NULL_RTX, SUBREG_REG (x), NULL_PTR, &SUBREG_REG (x), - find_valid_class (subreg_mode, SUBREG_WORD (x)), + find_valid_class (subreg_mode, + SUBREG_BYTE (x) / GET_MODE_SIZE (subreg_mode)), VOIDmode, subreg_mode, 0, 0, opnum, type); else push_reload (SUBREG_REG (x), NULL_RTX, &SUBREG_REG (x), NULL_PTR, - find_valid_class (subreg_mode, SUBREG_WORD (x)), + find_valid_class (subreg_mode, + SUBREG_BYTE (x) / GET_MODE_SIZE (subreg_mode)), subreg_mode, VOIDmode, 0, 0, opnum, type); } @@ -5075,7 +5118,11 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) code0 = GET_CODE (op0); if (code0 == REG && REGNO (op0) < FIRST_PSEUDO_REGISTER) op0 = gen_rtx_REG (word_mode, - REGNO (op0) + SUBREG_WORD (orig_op0)); + (REGNO (op0) + + subreg_regno_offset (REGNO (SUBREG_REG (orig_op0)), + GET_MODE (SUBREG_REG (orig_op0)), + SUBREG_BYTE (orig_op0), + GET_MODE (orig_op0)))); } if (GET_CODE (op1) == SUBREG) @@ -5083,8 +5130,14 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) op1 = SUBREG_REG (op1); code1 = GET_CODE (op1); if (code1 == REG && REGNO (op1) < FIRST_PSEUDO_REGISTER) + /* ??? Why is this given op1's mode and above for + ??? op0 SUBREGs we use word_mode? */ op1 = gen_rtx_REG (GET_MODE (op1), - REGNO (op1) + SUBREG_WORD (orig_op1)); + (REGNO (op1) + + subreg_regno_offset (REGNO (SUBREG_REG (orig_op1)), + GET_MODE (SUBREG_REG (orig_op1)), + SUBREG_BYTE (orig_op1), + GET_MODE (orig_op1)))); } if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE @@ -5492,7 +5545,7 @@ 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 = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x); + int regno = subreg_regno (x); if (! (context ? REGNO_OK_FOR_INDEX_P (regno) : REGNO_MODE_OK_FOR_BASE_P (regno, mode))) @@ -5646,15 +5699,10 @@ find_reloads_subreg_address (x, force_replace, opnum, type, if (force_replace || ! rtx_equal_p (tem, reg_equiv_mem[regno])) { - int offset = SUBREG_WORD (x) * UNITS_PER_WORD; + int offset = SUBREG_BYTE (x); unsigned outer_size = GET_MODE_SIZE (GET_MODE (x)); unsigned inner_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))); - if (BYTES_BIG_ENDIAN) - { - offset += MIN (inner_size, UNITS_PER_WORD); - offset -= MIN (outer_size, UNITS_PER_WORD); - } XEXP (tem, 0) = plus_constant (XEXP (tem, 0), offset); PUT_MODE (tem, GET_MODE (x)); @@ -5741,8 +5789,18 @@ subst_reloads (insn) *r->subreg_loc = SUBREG_REG (reloadreg); else { + int final_offset = + SUBREG_BYTE (*r->subreg_loc) + SUBREG_BYTE (reloadreg); + + /* When working with SUBREGs the rule is that the byte + offset must be a multiple of the SUBREG's mode. */ + final_offset = (final_offset / + GET_MODE_SIZE (GET_MODE (*r->subreg_loc))); + final_offset = (final_offset * + GET_MODE_SIZE (GET_MODE (*r->subreg_loc))); + *r->where = SUBREG_REG (reloadreg); - SUBREG_WORD (*r->subreg_loc) += SUBREG_WORD (reloadreg); + SUBREG_BYTE (*r->subreg_loc) = final_offset; } } else @@ -5843,12 +5901,24 @@ find_replacement (loc) if (GET_CODE (reloadreg) == REG) return gen_rtx_REG (GET_MODE (*loc), - REGNO (reloadreg) + SUBREG_WORD (*loc)); + (REGNO (reloadreg) + + subreg_regno_offset (REGNO (SUBREG_REG (*loc)), + GET_MODE (SUBREG_REG (*loc)), + SUBREG_BYTE (*loc), + GET_MODE (*loc)))); else if (GET_MODE (reloadreg) == GET_MODE (*loc)) return reloadreg; else - return gen_rtx_SUBREG (GET_MODE (*loc), SUBREG_REG (reloadreg), - SUBREG_WORD (reloadreg) + SUBREG_WORD (*loc)); + { + int final_offset = SUBREG_BYTE (reloadreg) + SUBREG_BYTE (*loc); + + /* When working with SUBREGs the rule is that the byte + offset must be a multiple of the SUBREG's mode. */ + final_offset = (final_offset / GET_MODE_SIZE (GET_MODE (*loc))); + final_offset = (final_offset * GET_MODE_SIZE (GET_MODE (*loc))); + return gen_rtx_SUBREG (GET_MODE (*loc), SUBREG_REG (reloadreg), + final_offset); + } } } @@ -5925,7 +5995,7 @@ refers_to_regno_for_reload_p (regno, endregno, x, loc) if (GET_CODE (SUBREG_REG (x)) == REG && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER) { - unsigned int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x); + unsigned int inner_regno = subreg_regno (x); unsigned int inner_endregno = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1); @@ -6020,7 +6090,10 @@ reg_overlap_mentioned_for_reload_p (x, in) { regno = REGNO (SUBREG_REG (x)); if (regno < FIRST_PSEUDO_REGISTER) - regno += SUBREG_WORD (x); + regno += subreg_regno_offset (REGNO (SUBREG_REG (x)), + GET_MODE (SUBREG_REG (x)), + SUBREG_BYTE (x), + GET_MODE (x)); } else if (GET_CODE (x) == REG) { |