Hi! cselib (probably among others) isn't prepared to handle arbitrarily complex debug insns. The debug insns are usually created from debug stmts which shouldn't have unbound complexity, but with TER we can actually end up with arbitrarily large debug insns.
This patch fixes that up during expansion, by splitting subexpressions of too large debug insn expressions into their own debug temporaries. So far bootstrapped/regtested on x86_64-linux and i686-linux without the first two hunks (it caused one failure on the latter because of invalid RTL sharing), I'm going to bootstrap/regtest it again, ok for trunk if it passes? 2013-03-05 Jakub Jelinek <ja...@redhat.com> PR debug/56510 * cfgexpand.c (expand_debug_parm_decl): Call copy_rtx on incoming. (avoid_complex_debug_insns): New function. (expand_debug_locations): Call it. * gcc.dg/pr56510.c: New test. --- gcc/cfgexpand.c.jj 2013-03-05 15:12:15.071565689 +0100 +++ gcc/cfgexpand.c 2013-03-05 17:21:55.683602432 +0100 @@ -2622,6 +2622,8 @@ expand_debug_parm_decl (tree decl) reg = gen_raw_REG (GET_MODE (reg), OUTGOING_REGNO (REGNO (reg))); incoming = replace_equiv_address_nv (incoming, reg); } + else + incoming = copy_rtx (incoming); } #endif @@ -2637,7 +2639,7 @@ expand_debug_parm_decl (tree decl) || (GET_CODE (XEXP (incoming, 0)) == PLUS && XEXP (XEXP (incoming, 0), 0) == virtual_incoming_args_rtx && CONST_INT_P (XEXP (XEXP (incoming, 0), 1))))) - return incoming; + return copy_rtx (incoming); return NULL_RTX; } @@ -3704,6 +3706,54 @@ expand_debug_source_expr (tree exp) return op0; } +/* Ensure INSN_VAR_LOCATION_LOC (insn) doesn't have unbound complexity. + Allow 4 levels of rtl nesting for most rtl codes, and if we see anything + deeper than that, create DEBUG_EXPRs and emit DEBUG_INSNs before INSN. */ + +static void +avoid_complex_debug_insns (rtx insn, rtx *exp_p, int depth) +{ + rtx exp = *exp_p; + if (exp == NULL_RTX) + return; + if ((OBJECT_P (exp) && !MEM_P (exp)) || GET_CODE (exp) == CLOBBER) + return; + + if (depth == 4) + { + /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL). */ + rtx dval = make_debug_expr_from_rtl (exp); + + /* Emit a debug bind insn before INSN. */ + rtx bind = gen_rtx_VAR_LOCATION (GET_MODE (exp), + DEBUG_EXPR_TREE_DECL (dval), exp, + VAR_INIT_STATUS_INITIALIZED); + + emit_debug_insn_before (bind, insn); + *exp_p = dval; + return; + } + + const char *format_ptr = GET_RTX_FORMAT (GET_CODE (exp)); + int i, j; + for (i = 0; i < GET_RTX_LENGTH (GET_CODE (exp)); i++) + switch (*format_ptr++) + { + case 'e': + avoid_complex_debug_insns (insn, &XEXP (exp, i), depth + 1); + break; + + case 'E': + case 'V': + for (j = 0; j < XVECLEN (exp, i); j++) + avoid_complex_debug_insns (insn, &XVECEXP (exp, i, j), depth + 1); + break; + + default: + break; + } +} + /* Expand the _LOCs in debug insns. We run this after expanding all regular insns, so that any variables referenced in the function will have their DECL_RTLs set. */ @@ -3724,7 +3774,7 @@ expand_debug_locations (void) if (DEBUG_INSN_P (insn)) { tree value = (tree)INSN_VAR_LOCATION_LOC (insn); - rtx val; + rtx val, prev_insn, insn2; enum machine_mode mode; if (value == NULL_TREE) @@ -3753,6 +3803,9 @@ expand_debug_locations (void) } INSN_VAR_LOCATION_LOC (insn) = val; + prev_insn = PREV_INSN (insn); + for (insn2 = insn; insn2 != prev_insn; insn2 = PREV_INSN (insn2)) + avoid_complex_debug_insns (insn2, &INSN_VAR_LOCATION_LOC (insn2), 0); } flag_strict_aliasing = save_strict_alias; --- gcc/testsuite/gcc.dg/pr56510.c.jj 2013-03-05 16:57:54.498939220 +0100 +++ gcc/testsuite/gcc.dg/pr56510.c 2013-03-05 16:57:54.499939214 +0100 @@ -0,0 +1,37 @@ +/* PR debug/56510 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -g" } */ + +struct S { unsigned long s1; void **s2[0]; }; +void **a, **b, **c, **d, **e, **f; + +static void ** +baz (long x, long y) +{ + void **s = f; + *f = (void **) (y << 8 | (x & 0xff)); + f += y + 1; + return s; +} + +void bar (void); +void +foo (void) +{ + void **g = b[4]; + a = b[2]; + b = b[1]; + g[2] = e; + void **h + = ((void **************************) + a)[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][66]; + void **i = ((struct S *) h)->s2[4]; + d = baz (4, 3); + d[1] = b; + d[2] = a; + d[3] = bar; + b = d; + g[1] = i[2]; + a = g; + ((void (*) (void)) (i[1])) (); +} Jakub