Hi Vladimir, The following testcase fails when compiled with -O2 -mips32r2:
long long a[]; long long b, c, d, k, m, n, o, p, q, r, s, t, u, v, w; int e, f, g, h, i, j, l, x; fn1() { for (; x; x++) if (x & 1) s = h | g; else s = f | e; l = ~0; m = 1 | k; n = i; o = j; p = f | e; q = h | g; w = d | c | a[1]; t = c; v = b | c; u = v; r = b | a[4]; } It is reproducible on mips-linux-gnu using SVN revision 212763. After a patch to p5600.md the bug is not triggered but it may reappear in the future. The decompose_normal_address function throws an assertion because it cannot decompose the following RTL: (mem/c:SI (lo_sum:SI (high:SI (symbol_ref:SI ("w"))) (const:SI (plus:SI (symbol_ref:SI ("w")) (const_int 4 [0x4])) It appears that it all starts in the following instruction and how LRA deals with REG_EQUIV notes: (insn 107 119 123 10 (set (reg:SI 283) (ior:SI (reg:SI 284 [ a+12 ]) (reg:SI 309 [ D.1467+4 ]))) init.i:16 163 {*iorsi3} (expr_list:REG_DEAD (reg:SI 309 [ D.1467+4 ]) (expr_list:REG_DEAD (reg:SI 284 [ a+12 ]) (expr_list:REG_EQUIV (mem/c:SI (lo_sum:SI (reg/f:SI 274) (const:SI (plus:SI (symbol_ref:SI ("w")) (const_int 4 [0x4]))))) (nil))))) There are two conditions necessary to trigger the ICE. Firstly, the pseudo 274 is spilled to memory that is marked by IRA, thus, during LRA pass the pseudo 274 is replaced with 'high' when equivalences are updated for pseudos. Secondly, pseudo 283 also gets spilled and LRA starts using equivalences but LO_SUM and HIGH are already combined leading to an assertion error. Accepting HIGH as the base does seem to solve the problem. HIGH is also reloaded after the decomposition splitting HIGH/LO_SUM into a pair again. However, is this an acceptable solution? Regards, Robert gcc/ * rtlanal.c (get_base_term): Accept HIGH as the base term. diff --git gcc/rtlanal.c gcc/rtlanal.c index 82cfc1bf..2bea2ca 100644 --- gcc/rtlanal.c +++ gcc/rtlanal.c @@ -5624,6 +5624,7 @@ get_base_term (rtx *inner) inner = strip_address_mutations (&XEXP (*inner, 0)); if (REG_P (*inner) || MEM_P (*inner) + || GET_CODE (*inner) == HIGH || GET_CODE (*inner) == SUBREG) return inner; return 0;