diff --git a/gcc/rtl.h b/gcc/rtl.h index 2370d6081614ba9e2f12d77e56cd7a4a876548cf..1ef6432fd9c16927b221c5f52c36a68f362c91ea 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -2225,11 +2225,21 @@ struct address_info { reloading. - *BASE is a variable expression representing a base address. - It contains exactly one REG, SUBREG or MEM, pointed to by BASE_TERM. + It contains exactly one "term", pointed to by BASE_TERM. + This term can be one of the following: + + (1) a REG, or a SUBREG of a REG + (2) an eliminated REG (a PLUS of (1) and a constant) + (3) a MEM, or a SUBREG of a MEM + (4) a SCRATCH + + This term is the one that base_reg_class constrains. - *INDEX is a variable expression representing an index value. It may be a scaled expression, such as a MULT. It has exactly - one REG, SUBREG or MEM, pointed to by INDEX_TERM. + one "term", pointed to by INDEX_TERM. The possible terms are + the same as for BASE. This term is the one that index_reg_class + constrains. - *DISP is a constant, possibly mutated. DISP_TERM points to the unmutated RTX_CONST_OBJ. */ diff --git a/gcc/rtlanal.cc b/gcc/rtlanal.cc index 71207ee4f417ac40f8c8dea5dcda78956ef89108..8afbb32f2206096f094e92e9f7a615804a568b8e 100644 --- a/gcc/rtlanal.cc +++ b/gcc/rtlanal.cc @@ -6494,6 +6494,25 @@ binary_scale_code_p (enum rtx_code code) || code == ROTATERT); } +/* Return true if X appears to be a valid base or index term. */ +static bool +valid_base_or_index_term_p (rtx x) +{ + if (GET_CODE (x) == SCRATCH) + return true; + /* Handle what appear to be eliminated forms of a register. If we reach + here, the elimination occurs outside of the outermost PLUS tree, + and so the elimination offset cannot be treated as a displacement + of the main address. Instead, we need to treat the whole PLUS as + the base or index term. The address can only be made legitimate by + reloading the PLUS. */ + if (GET_CODE (x) == PLUS && CONST_SCALAR_INT_P (XEXP (x, 1))) + x = XEXP (x, 0); + if (GET_CODE (x) == SUBREG) + x = SUBREG_REG (x); + return REG_P (x) || MEM_P (x); +} + /* If *INNER can be interpreted as a base, return a pointer to the inner term (see address_info). Return null otherwise. */ @@ -6502,10 +6521,7 @@ get_base_term (rtx *inner) { if (GET_CODE (*inner) == LO_SUM) inner = strip_address_mutations (&XEXP (*inner, 0)); - if (REG_P (*inner) - || MEM_P (*inner) - || GET_CODE (*inner) == SUBREG - || GET_CODE (*inner) == SCRATCH) + if (valid_base_or_index_term_p (*inner)) return inner; return 0; } @@ -6519,10 +6535,7 @@ get_index_term (rtx *inner) /* At present, only constant scales are allowed. */ if (binary_scale_code_p (GET_CODE (*inner)) && CONSTANT_P (XEXP (*inner, 1))) inner = strip_address_mutations (&XEXP (*inner, 0)); - if (REG_P (*inner) - || MEM_P (*inner) - || GET_CODE (*inner) == SUBREG - || GET_CODE (*inner) == SCRATCH) + if (valid_base_or_index_term_p (*inner)) return inner; return 0; }