Hi! As the following two testcases show, while we have avoid_complex_debug_insns that decreases debug insn complexity after expansion is done, there is a problem during expansion if the TER chains are too deep, because simplify-rtx.c in some cases is inherently quadratic - does not like arbitrarily large RTL expressions.
The following patch fixes that by breaking the TER chains for debug insns by adding DEBUG_EXPR_DECLs temporaries. Some non-zero depth is desirable, we want to simplify things, but must avoid creating too large expressions that way. The patch inserts the debug bind stmts early during expansion, but of course can't adjust the uses of those SSA_NAMEs, because those are used by non-debug stmts too, so keeps the SSA_NAME -> DEBUG_EXPR_DECL mapping in a hash_map. Bootstrapped/regtested on x86_64-linux and i686-linux, with only very minimal effect on debug info, e.g. in x86_64-linux bootstrap only debug info of dominance.o, ipa-polymorphic-call.o and lto-streamer-out.o is affected, and only a few .debug_info/.debug_loc section byte differences. Ok for trunk? 2015-01-30 Jakub Jelinek <ja...@redhat.com> PR debug/64817 * cfgexpand.c (deep_ter_debug_map): New variable. (avoid_deep_ter_for_debug): New function. (expand_debug_expr): If TERed SSA_NAME is in deep_ter_debug_map, use the corresponding DEBUG_EXPR_DECL instead of trying to expand SSA_NAME's def stmt. (expand_debug_locations): When expanding debug bind of a DEBUG_EXPR_DECL to corresponding SSA_NAME, temporarily remove the DEBUG_EXPR_DECL from deep_ter_debug_map's value. (pass_expand::execute): Call avoid_deep_ter_for_debug on all debug bind stmts. Delete deep_ter_debug_map after expand_debug_location if non-NULL and clear it. * gcc.dg/pr64817-1.c: New test. * gcc.dg/pr64817-2.c: New test. --- gcc/cfgexpand.c.jj 2015-01-28 21:24:56.000000000 +0100 +++ gcc/cfgexpand.c 2015-01-30 13:22:46.002579984 +0100 @@ -3767,6 +3767,48 @@ convert_debug_memory_address (machine_mo return x; } +/* Map from SSA_NAMEs to corresponding DEBUG_EXPR_DECLs created + by avoid_deep_ter_for_debug. */ + +hash_map<tree, tree> *deep_ter_debug_map; + +/* Split too deep TER chains for debug stmts using debug temporaries. */ + +static void +avoid_deep_ter_for_debug (gimple stmt, int depth) +{ + use_operand_p use_p; + ssa_op_iter iter; + FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE) + { + tree use = USE_FROM_PTR (use_p); + if (TREE_CODE (use) != SSA_NAME || SSA_NAME_IS_DEFAULT_DEF (use)) + continue; + gimple g = get_gimple_for_ssa_name (use); + if (g == NULL) + continue; + if (depth > 6 && !stmt_ends_bb_p (g)) + { + if (deep_ter_debug_map == NULL) + deep_ter_debug_map = new hash_map<tree, tree>; + + tree &vexpr = deep_ter_debug_map->get_or_insert (use); + if (vexpr != NULL) + continue; + vexpr = make_node (DEBUG_EXPR_DECL); + gimple def_temp = gimple_build_debug_bind (vexpr, use, g); + DECL_ARTIFICIAL (vexpr) = 1; + TREE_TYPE (vexpr) = TREE_TYPE (use); + DECL_MODE (vexpr) = TYPE_MODE (TREE_TYPE (use)); + gimple_stmt_iterator gsi = gsi_for_stmt (g); + gsi_insert_after (&gsi, def_temp, GSI_NEW_STMT); + avoid_deep_ter_for_debug (def_temp, 0); + } + else + avoid_deep_ter_for_debug (g, depth + 1); + } +} + /* Return an RTX equivalent to the value of the parameter DECL. */ static rtx @@ -4654,7 +4696,16 @@ expand_debug_expr (tree exp) gimple g = get_gimple_for_ssa_name (exp); if (g) { - op0 = expand_debug_expr (gimple_assign_rhs_to_tree (g)); + tree t = NULL_TREE; + if (deep_ter_debug_map) + { + tree *slot = deep_ter_debug_map->get (exp); + if (slot) + t = *slot; + } + if (t == NULL_TREE) + t = gimple_assign_rhs_to_tree (g); + op0 = expand_debug_expr (t); if (!op0) return NULL; } @@ -4961,6 +5012,25 @@ expand_debug_locations (void) if (INSN_VAR_LOCATION_STATUS (insn) == VAR_INIT_STATUS_UNINITIALIZED) val = expand_debug_source_expr (value); + /* The avoid_deep_ter_for_debug function inserts + debug bind stmts after SSA_NAME definition, with the + SSA_NAME as the whole bind location. Disable temporarily + expansion of that SSA_NAME into the DEBUG_EXPR_DECL + being defined in this DEBUG_INSN. */ + else if (deep_ter_debug_map && TREE_CODE (value) == SSA_NAME) + { + tree *slot = deep_ter_debug_map->get (value); + if (slot) + { + if (*slot == INSN_VAR_LOCATION_DECL (insn)) + *slot = NULL_TREE; + else + slot = NULL; + } + val = expand_debug_expr (value); + if (slot) + *slot = INSN_VAR_LOCATION_DECL (insn); + } else val = expand_debug_expr (value); gcc_assert (last == get_last_insn ()); @@ -5821,6 +5891,15 @@ pass_expand::execute (function *fun) timevar_pop (TV_OUT_OF_SSA); SA.partition_to_pseudo = XCNEWVEC (rtx, SA.map->num_partitions); + if (MAY_HAVE_DEBUG_STMTS && flag_tree_ter) + { + gimple_stmt_iterator gsi; + FOR_EACH_BB_FN (bb, cfun) + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + if (gimple_debug_bind_p (gsi_stmt (gsi))) + avoid_deep_ter_for_debug (gsi_stmt (gsi), 0); + } + /* Make sure all values used by the optimization passes have sane defaults. */ reg_renumber = 0; @@ -6008,6 +6087,12 @@ pass_expand::execute (function *fun) if (MAY_HAVE_DEBUG_INSNS) expand_debug_locations (); + if (deep_ter_debug_map) + { + delete deep_ter_debug_map; + deep_ter_debug_map = NULL; + } + /* Free stuff we no longer need after GIMPLE optimizations. */ free_dominance_info (CDI_DOMINATORS); free_dominance_info (CDI_POST_DOMINATORS); --- gcc/testsuite/gcc.dg/pr64817-1.c.jj 2015-01-30 13:33:05.061143850 +0100 +++ gcc/testsuite/gcc.dg/pr64817-1.c 2015-01-30 13:32:33.000000000 +0100 @@ -0,0 +1,20 @@ +/* PR debug/64817 */ +/* { dg-do compile } */ +/* { dg-options "-O3 -g" } */ + +int a, b, d; + +void +foo (void) +{ + for (b = 0; b < 9; b++) + { + int e; + for (d = 0; d < 5; d++) + { + a &= 231; + a ^= 14; + } + e = (a ^= 1) < 0; + } +} --- gcc/testsuite/gcc.dg/pr64817-2.c.jj 2015-01-20 10:01:16.345964420 +0100 +++ gcc/testsuite/gcc.dg/pr64817-2.c 2015-01-30 18:37:49.055911292 +0100 @@ -0,0 +1,13 @@ +/* PR debug/64817 */ +/* { dg-do compile } */ +/* { dg-options "-O3 -g" } */ + +int a; + +void +foo (void) +{ + int e; + a = ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((a & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) & 231) ^ 14) ^ 1; + e = (a < 0); +} Jakub