diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/reload.c | 104 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/pr58901-0.c | 17 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/pr58901-1.c | 21 |
3 files changed, 106 insertions, 36 deletions
diff --git a/gcc/reload.c b/gcc/reload.c index a63cc02..b99b72c 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -1043,53 +1043,72 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, Also reload the inner expression if it does not require a secondary reload but the SUBREG does. - Finally, reload the inner expression if it is a register that is in + Also 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_lowpart_p is false, 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. */ + no choice, so we hope we do get the right register class there. + + Finally, reload the inner expression if it is a pseudo that will + become a MEM and the MEM has a mode-dependent address, as in that + case we obviously cannot change the mode of the MEM to that of the + containing SUBREG as that would change the interpretation of the + address. */ scalar_int_mode inner_mode; if (in != 0 && GET_CODE (in) == SUBREG - && (subreg_lowpart_p (in) || strict_low) && targetm.can_change_mode_class (GET_MODE (SUBREG_REG (in)), inmode, rclass) && contains_allocatable_reg_of_mode[rclass][GET_MODE (SUBREG_REG (in))] - && (CONSTANT_P (SUBREG_REG (in)) - || GET_CODE (SUBREG_REG (in)) == PLUS - || strict_low - || (((REG_P (SUBREG_REG (in)) - && REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER) - || MEM_P (SUBREG_REG (in))) - && (paradoxical_subreg_p (inmode, GET_MODE (SUBREG_REG (in))) - || (known_le (GET_MODE_SIZE (inmode), UNITS_PER_WORD) - && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (in)), - &inner_mode) - && GET_MODE_SIZE (inner_mode) <= UNITS_PER_WORD - && paradoxical_subreg_p (inmode, inner_mode) - && LOAD_EXTEND_OP (inner_mode) != UNKNOWN) - || (WORD_REGISTER_OPERATIONS - && partial_subreg_p (inmode, GET_MODE (SUBREG_REG (in))) - && (known_equal_after_align_down - (GET_MODE_SIZE (inmode) - 1, - GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) - 1, - UNITS_PER_WORD))))) - || (REG_P (SUBREG_REG (in)) - && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER - /* The case where out is nonzero - is handled differently in the following statement. */ - && (out == 0 || subreg_lowpart_p (in)) - && (complex_word_subreg_p (inmode, SUBREG_REG (in)) - || !targetm.hard_regno_mode_ok (subreg_regno (in), inmode))) - || (secondary_reload_class (1, rclass, inmode, in) != NO_REGS - && (secondary_reload_class (1, rclass, GET_MODE (SUBREG_REG (in)), - SUBREG_REG (in)) - == NO_REGS)) + && (strict_low + || (subreg_lowpart_p (in) + && (CONSTANT_P (SUBREG_REG (in)) + || GET_CODE (SUBREG_REG (in)) == PLUS + || (((REG_P (SUBREG_REG (in)) + && REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER) + || MEM_P (SUBREG_REG (in))) + && (paradoxical_subreg_p (inmode, + GET_MODE (SUBREG_REG (in))) + || (known_le (GET_MODE_SIZE (inmode), UNITS_PER_WORD) + && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG + (in)), + &inner_mode) + && GET_MODE_SIZE (inner_mode) <= UNITS_PER_WORD + && paradoxical_subreg_p (inmode, inner_mode) + && LOAD_EXTEND_OP (inner_mode) != UNKNOWN) + || (WORD_REGISTER_OPERATIONS + && partial_subreg_p (inmode, + GET_MODE (SUBREG_REG (in))) + && (known_equal_after_align_down + (GET_MODE_SIZE (inmode) - 1, + GET_MODE_SIZE (GET_MODE (SUBREG_REG + (in))) - 1, + UNITS_PER_WORD))))) + || (REG_P (SUBREG_REG (in)) + && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER + /* The case where out is nonzero + is handled differently in the following statement. */ + && (out == 0 || subreg_lowpart_p (in)) + && (complex_word_subreg_p (inmode, SUBREG_REG (in)) + || !targetm.hard_regno_mode_ok (subreg_regno (in), + inmode))) + || (secondary_reload_class (1, rclass, inmode, in) != NO_REGS + && (secondary_reload_class (1, rclass, + GET_MODE (SUBREG_REG (in)), + SUBREG_REG (in)) + == NO_REGS)) + || (REG_P (SUBREG_REG (in)) + && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER + && !REG_CAN_CHANGE_MODE_P (REGNO (SUBREG_REG (in)), + GET_MODE (SUBREG_REG (in)), + inmode)))) || (REG_P (SUBREG_REG (in)) - && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER - && !REG_CAN_CHANGE_MODE_P (REGNO (SUBREG_REG (in)), - GET_MODE (SUBREG_REG (in)), inmode)))) + && REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER + && reg_equiv_mem (REGNO (SUBREG_REG (in))) + && (mode_dependent_address_p + (XEXP (reg_equiv_mem (REGNO (SUBREG_REG (in))), 0), + MEM_ADDR_SPACE (reg_equiv_mem (REGNO (SUBREG_REG (in))))))))) { #ifdef LIMIT_RELOAD_CLASS in_subreg_loc = inloc; @@ -3157,6 +3176,19 @@ find_reloads (rtx_insn *insn, int replace, int ind_levels, int live_known, && paradoxical_subreg_p (operand_mode[i], inner_mode) && LOAD_EXTEND_OP (inner_mode) != UNKNOWN))) + /* We must force a reload of a SUBREG's inner expression + if it is a pseudo that will become a MEM and the MEM + has a mode-dependent address, as in that case we + obviously cannot change the mode of the MEM to that + of the containing SUBREG as that would change the + interpretation of the address. */ + || (REG_P (operand) + && REGNO (operand) >= FIRST_PSEUDO_REGISTER + && reg_equiv_mem (REGNO (operand)) + && (mode_dependent_address_p + (XEXP (reg_equiv_mem (REGNO (operand)), 0), + (MEM_ADDR_SPACE + (reg_equiv_mem (REGNO (operand))))))) ) force_reload = 1; } diff --git a/gcc/testsuite/gcc.c-torture/compile/pr58901-0.c b/gcc/testsuite/gcc.c-torture/compile/pr58901-0.c new file mode 100644 index 0000000..d98e29e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr58901-0.c @@ -0,0 +1,17 @@ +typedef int __attribute__ ((mode (SI))) int_t; + +struct s +{ + int_t n; + int_t c[]; +}; + +int_t +ashlsi (int_t x, const struct s *s) +{ + int_t i; + + for (i = 0; i < s->n; i++) + x ^= 1 << s->c[i]; + return x; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr58901-1.c b/gcc/testsuite/gcc.c-torture/compile/pr58901-1.c new file mode 100644 index 0000000..e01dba0 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr58901-1.c @@ -0,0 +1,21 @@ +typedef signed int __attribute__ ((mode (SI))) int_t; + +struct s +{ + int_t n; + int_t m : 1; + int_t l : 31; +}; + +int_t +movdi (int_t x, const struct s *s) +{ + int_t i; + + for (i = 0; i < x; i++) + { + const struct s t = s[i]; + x += t.m ? 1 : 0; + } + return x; +} |