MIPS: smarter code for constant addresses See http://gcc.gnu.org/ml/gcc/2008-11/msg00231.html Backport of the original patch (by Richard Sandiford) to 4.3.2/4.3.3 --- a/gcc/config/mips/mips.c.orig 2009-01-21 08:54:56.526374343 +0100 +++ b/gcc/config/mips/mips.c 2009-01-21 08:55:03.229865079 +0100 @@ -2481,7 +2481,26 @@ mips_legitimize_tls_address (rtx loc) } return dest; } - + +/* Return true if, for every base register BASE_REG, (plus BASE_REG X) + can address a value of mode MODE. */ + +static bool +mips_valid_offset_p (rtx x, enum machine_mode mode) +{ + /* Check that X is a signed 16-bit number. */ + if (!const_arith_operand (x, Pmode)) + return false; + + /* We may need to split multiword moves, so make sure that every word + is accessible. */ + if (GET_MODE_SIZE (mode) > UNITS_PER_WORD + && !SMALL_OPERAND (INTVAL (x) + GET_MODE_SIZE (mode) - UNITS_PER_WORD)) + return false; + + return true; +} + /* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can be legitimized in a way that the generic machinery might not expect, put the new address in *XLOC and return true. MODE is the mode of @@ -2491,7 +2510,7 @@ bool mips_legitimize_address (rtx *xloc, enum machine_mode mode) { rtx base; - HOST_WIDE_INT offset; + HOST_WIDE_INT intval, high, offset; if (mips_tls_symbol_p (*xloc)) { @@ -2512,6 +2531,33 @@ mips_legitimize_address (rtx *xloc, enum *xloc = mips_add_offset (NULL, base, offset); return true; } + + /* Handle references to constant addresses by loading the high part + into a register and using an offset for the low part. */ + if (GET_CODE (base) == CONST_INT) + { + intval = INTVAL (base); + high = trunc_int_for_mode (CONST_HIGH_PART (intval), Pmode); + offset = CONST_LOW_PART (intval); + /* Ignore cases in which a positive address would be accessed by a + negative offset from a negative address. The required wraparound + does not occur for 32-bit addresses on 64-bit targets, and it is + very unlikely that such an access would occur in real code anyway. + + If the low offset is not legitimate for MODE, prefer to load + the constant normally, instead of using mips_force_address on + the legitimized address. The latter option would cause us to + use (D)ADDIU unconditionally, but LUI/ORI is more efficient + than LUI/ADDIU on some targets. */ + if ((intval < 0 || high > 0) + && mips_valid_offset_p (GEN_INT (offset), mode)) + { + base = mips_force_temporary (NULL, GEN_INT (high)); + *xloc = plus_constant (base, offset); + return true; + } + } + return false; }