Hello! In a corner case of a reload, reload pass can generate partially reloaded address, where not all registers get allocated to a hard reg. When this address is checked with ix86_legitimate_address, it is rejected, since in strict mode, pseudos are not valid address registers. So, reload tries to legitimize following (partially invalid) address:
(plus:DI (plus:DI (unspec:DI [(const_int 0 [0])] UNSPEC_TP) (reg:DI 97)) (reg:DI 2 cx)) via generic way by pushing all components into a register, forming (even more invalid) address that involves three registers (r8, r9 and rcx): (insn 52 78 53 5 (set (mem/j:QI (plus:DI (plus:DI (reg:DI 37 r8) (reg:DI 38 r9)) (reg:DI 2 cx [orig:98 D.1709 ] [98])) [0 foo S1 A8]) (reg:QI 1 dx [100])) /tmp/x.c:12 66 {*movqi_internal} (nil)) BTW: x86 declares MAX_REGISTER_PER_ADDRESS to 2... Attached patch fixes this situation by (partially) reloading only remaining pseudo(s), leaving UNSPEC in the address RTX. 2012-03-26 Uros Bizjak <ubiz...@gmail.com> PR target/52698 * config/i386/i386-protos.h (ix86_legitimize_reload_address): New prototype. * config/i386/i386.h (LEGITIMIZE_RELOAD_ADDRESS): New define. * config/i386/i386.c: Include reload.h. (ix86_legitimize_reload_address): New function. testsuite/ChangeLog: 2012-03-26 Uros Bizjak <ubiz...@gmail.com> H.J. Lu <hongjiu...@intel.com> PR target/52698 * gcc.target/i386/pr52698.c: New test. The patch was bootstrapped and regression tested on x86_64-pc-linux-gnu {,-m32}. Since fixing reload issues is some kind of black magic, I'd like to ask Ulrich and Richard for their opinion on this approach. H.J., can you please test this fix on x32 testsuite for both address modes? Thanks, Uros.
Index: config/i386/i386.c =================================================================== --- config/i386/i386.c (revision 185807) +++ config/i386/i386.c (working copy) @@ -47,6 +47,7 @@ #include "target-def.h" #include "common/common-target.h" #include "langhooks.h" +#include "reload.h" #include "cgraph.h" #include "gimple.h" #include "dwarf2.h" @@ -12010,6 +12011,64 @@ return false; } +/* Our implementation of LEGITIMIZE_RELOAD_ADDRESS. Returns a value to + replace the input X, or the original X if no replacement is called for. + The output parameter *WIN is 1 if the calling macro should goto WIN, + 0 if it should not. */ + +bool +ix86_legitimize_reload_address (rtx x, + enum machine_mode mode ATTRIBUTE_UNUSED, + int opnum, int type, + int ind_levels ATTRIBUTE_UNUSED) +{ + /* Reload can generate: + + (plus:DI (plus:DI (unspec:DI [(const_int 0 [0])] UNSPEC_TP) + (reg:DI 97)) + (reg:DI 2 cx)) + + This RTX is rejected from ix86_legitimate_address_p due to + non-strictness of base register 97. Following this rejection, + reload pushes all three components into separate registers, + creating invalid memory address RTX. + + Following code reloads only the invalid part of the + memory address RTX. */ + + if (GET_CODE (x) == PLUS + && REG_P (XEXP (x, 1)) + && GET_CODE (XEXP (x, 0)) == PLUS + && REG_P (XEXP (XEXP (x, 0), 1))) + { + rtx base, index; + bool something_reloaded = false; + + base = XEXP (XEXP (x, 0), 1); + if (!REG_OK_FOR_BASE_STRICT_P (base)) + { + push_reload (base, NULL_RTX, &XEXP (XEXP (x, 0), 1), NULL, + BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0, + opnum, (enum reload_type)type); + something_reloaded = true; + } + + index = XEXP (x, 1); + if (!REG_OK_FOR_INDEX_STRICT_P (index)) + { + push_reload (index, NULL_RTX, &XEXP (x, 1), NULL, + INDEX_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0, + opnum, (enum reload_type)type); + something_reloaded = true; + } + + gcc_assert (something_reloaded); + return true; + } + + return false; +} + /* Recognizes RTL expressions that are valid memory addresses for an instruction. The MODE argument is the machine mode for the MEM expression that wants to use this address. Index: config/i386/i386.h =================================================================== --- config/i386/i386.h (revision 185807) +++ config/i386/i386.h (working copy) @@ -1630,6 +1630,17 @@ #define CONSTANT_ADDRESS_P(X) constant_address_p (X) +/* Try a machine-dependent way of reloading an illegitimate address + operand. If we find one, push the reload and jump to WIN. This + macro is used in only one place: `find_reloads_address' in reload.c. */ + +#define LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, INDL, WIN) \ +do { \ + if (ix86_legitimize_reload_address ((X), (MODE), (OPNUM), \ + (int)(TYPE), (INDL))) \ + goto WIN; \ +} while (0) + /* If defined, a C expression to determine the base term of address X. This macro is used in only one place: `find_base_term' in alias.c. Index: config/i386/i386-protos.h =================================================================== --- config/i386/i386-protos.h (revision 185807) +++ config/i386/i386-protos.h (working copy) @@ -65,7 +65,8 @@ extern bool constant_address_p (rtx); extern bool legitimate_pic_operand_p (rtx); extern bool legitimate_pic_address_disp_p (rtx); - +extern bool ix86_legitimize_reload_address (rtx, enum machine_mode, + int, int, int); extern void print_reg (rtx, int, FILE*); extern void ix86_print_operand (FILE *, rtx, int); Index: testsuite/gcc.target/i386/pr52698.c =================================================================== --- testsuite/gcc.target/i386/pr52698.c (revision 0) +++ testsuite/gcc.target/i386/pr52698.c (revision 0) @@ -0,0 +1,18 @@ +/* { dg-do compile { target { ! { ia32 } } } } */ +/* { dg-options "-O2 -mx32 -maddress-mode=long" } */ + +extern void abort (void); +static __thread unsigned char foo [32] +__attribute__ ((tls_model ("initial-exec"), aligned (sizeof (void *)))); + +void +test2 (void) +{ + unsigned int s; + for (s = 0; s < sizeof (foo); ++s) + { + if (foo [s] != s) + abort (); + foo [s] = sizeof (foo) - s; + } +}