diff options
author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-02-26 11:01:28 +0000 |
---|---|---|
committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-02-26 11:01:28 +0000 |
commit | 2058ec71c12051e69d8f7185bc0fa3e84b97b52a (patch) | |
tree | fa702f56527bb502176978eaa062fe31ff745b7a /gcc/regcprop.c | |
parent | 414f0dcbdd334b2f314a5179fb44dabcdcbe969e (diff) | |
download | gcc-2058ec71c12051e69d8f7185bc0fa3e84b97b52a.tar.gz |
PR debug/43161
* regcprop.c (struct queued_debug_insn_change): New type.
(struct value_data_entry): Add debug_insn_changes field.
(struct value_data): Add n_debug_insn_changes field.
(debug_insn_changes_pool): New variable.
(free_debug_insn_changes, apply_debug_insn_changes,
cprop_find_used_regs_1, cprop_find_used_regs): New functions.
(kill_value_one_regno): Call free_debug_insn_changes if needed.
(init_value_data): Clear debug_insn_changes and n_debug_insn_changes
fields.
(replace_oldest_value_reg): Don't change DEBUG_INSNs, instead queue
changes for them.
(copyprop_hardreg_forward_1): Don't call apply_change_group for
DEBUG_INSNs. For a real insn, if there are queued DEBUG_INSN
changes, call cprop_find_used_regs via note_stores.
(copyprop_hardreg_forward): When copying vd from predecessor
which has any queued DEBUG_INSN changes, make sure the pointers are
cleared. At the end call df_analyze and then if there are any
DEBUG_INSN changes queued at the end of some basic block for still
live registers, apply them.
(pass_cprop_hardreg): Set TODO_df_finish in todo_flags_finish.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@157083 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/regcprop.c')
-rw-r--r-- | gcc/regcprop.c | 178 |
1 files changed, 167 insertions, 11 deletions
diff --git a/gcc/regcprop.c b/gcc/regcprop.c index 609a06d26b4..2666f785389 100644 --- a/gcc/regcprop.c +++ b/gcc/regcprop.c @@ -46,6 +46,18 @@ up some silly register allocation decisions made by reload. This code may be obsoleted by a new register allocator. */ +/* DEBUG_INSNs aren't changed right away, as doing so might extend the + lifetime of a register and get the DEBUG_INSN subsequently reset. + So they are queued instead, and updated only when the register is + used in some subsequent real insn before it is set. */ +struct queued_debug_insn_change +{ + struct queued_debug_insn_change *next; + rtx insn; + rtx *loc; + rtx new_rtx; +}; + /* For each register, we have a list of registers that contain the same value. The OLDEST_REGNO field points to the head of the list, and the NEXT_REGNO field runs through the list. The MODE field indicates @@ -57,14 +69,18 @@ struct value_data_entry enum machine_mode mode; unsigned int oldest_regno; unsigned int next_regno; + struct queued_debug_insn_change *debug_insn_changes; }; struct value_data { struct value_data_entry e[FIRST_PSEUDO_REGISTER]; unsigned int max_value_regs; + unsigned int n_debug_insn_changes; }; +static alloc_pool debug_insn_changes_pool; + static void kill_value_one_regno (unsigned, struct value_data *); static void kill_value_regno (unsigned, unsigned, struct value_data *); static void kill_value (rtx, struct value_data *); @@ -91,6 +107,22 @@ extern void debug_value_data (struct value_data *); static void validate_value_data (struct value_data *); #endif +/* Free all queued updates for DEBUG_INSNs that change some reg to + register REGNO. */ + +static void +free_debug_insn_changes (struct value_data *vd, unsigned int regno) +{ + struct queued_debug_insn_change *cur, *next; + for (cur = vd->e[regno].debug_insn_changes; cur; cur = next) + { + next = cur->next; + --vd->n_debug_insn_changes; + pool_free (debug_insn_changes_pool, cur); + } + vd->e[regno].debug_insn_changes = NULL; +} + /* Kill register REGNO. This involves removing it from any value lists, and resetting the value mode to VOIDmode. This is only a helper function; it does not handle any hard registers overlapping @@ -118,6 +150,8 @@ kill_value_one_regno (unsigned int regno, struct value_data *vd) vd->e[regno].mode = VOIDmode; vd->e[regno].oldest_regno = regno; vd->e[regno].next_regno = INVALID_REGNUM; + if (vd->e[regno].debug_insn_changes) + free_debug_insn_changes (vd, regno); #ifdef ENABLE_CHECKING validate_value_data (vd); @@ -204,8 +238,10 @@ init_value_data (struct value_data *vd) vd->e[i].mode = VOIDmode; vd->e[i].oldest_regno = i; vd->e[i].next_regno = INVALID_REGNUM; + vd->e[i].debug_insn_changes = NULL; } vd->max_value_regs = 0; + vd->n_debug_insn_changes = 0; } /* Called through note_stores. If X is clobbered, kill its value. */ @@ -446,6 +482,24 @@ replace_oldest_value_reg (rtx *loc, enum reg_class cl, rtx insn, rtx new_rtx = find_oldest_value_reg (cl, *loc, vd); if (new_rtx) { + if (DEBUG_INSN_P (insn)) + { + struct queued_debug_insn_change *change; + + if (dump_file) + fprintf (dump_file, "debug_insn %u: queued replacing reg %u with %u\n", + INSN_UID (insn), REGNO (*loc), REGNO (new_rtx)); + + change = (struct queued_debug_insn_change *) + pool_alloc (debug_insn_changes_pool); + change->next = vd->e[REGNO (new_rtx)].debug_insn_changes; + change->insn = insn; + change->loc = loc; + change->new_rtx = new_rtx; + vd->e[REGNO (new_rtx)].debug_insn_changes = change; + ++vd->n_debug_insn_changes; + return true; + } if (dump_file) fprintf (dump_file, "insn %u: replaced reg %u with %u\n", INSN_UID (insn), REGNO (*loc), REGNO (new_rtx)); @@ -622,6 +676,58 @@ replace_oldest_value_mem (rtx x, rtx insn, struct value_data *vd) GET_MODE (x), insn, vd); } +/* Apply all queued updates for DEBUG_INSNs that change some reg to + register REGNO. */ + +static void +apply_debug_insn_changes (struct value_data *vd, unsigned int regno) +{ + struct queued_debug_insn_change *change; + rtx last_insn = vd->e[regno].debug_insn_changes->insn; + + for (change = vd->e[regno].debug_insn_changes; + change; + change = change->next) + { + if (last_insn != change->insn) + { + apply_change_group (); + last_insn = change->insn; + } + validate_change (change->insn, change->loc, change->new_rtx, 1); + } + apply_change_group (); +} + +/* Called via for_each_rtx, for all used registers in a real + insn apply DEBUG_INSN changes that change registers to the + used register. */ + +static int +cprop_find_used_regs_1 (rtx *loc, void *data) +{ + if (REG_P (*loc)) + { + struct value_data *vd = (struct value_data *) data; + if (vd->e[REGNO (*loc)].debug_insn_changes) + { + apply_debug_insn_changes (vd, REGNO (*loc)); + free_debug_insn_changes (vd, REGNO (*loc)); + } + } + return 0; +} + +/* Called via note_uses, for all used registers in a real insn + apply DEBUG_INSN changes that change registers to the used + registers. */ + +static void +cprop_find_used_regs (rtx *loc, void *vd) +{ + for_each_rtx (loc, cprop_find_used_regs_1, vd); +} + /* Perform the forward copy propagation on basic block BB. */ static bool @@ -643,15 +749,10 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd) if (DEBUG_INSN_P (insn)) { rtx loc = INSN_VAR_LOCATION_LOC (insn); - if (!VAR_LOC_UNKNOWN_P (loc) - && replace_oldest_value_addr (&INSN_VAR_LOCATION_LOC (insn), - ALL_REGS, GET_MODE (loc), - insn, vd)) - { - changed = apply_change_group (); - gcc_assert (changed); - anything_changed = true; - } + if (!VAR_LOC_UNKNOWN_P (loc)) + replace_oldest_value_addr (&INSN_VAR_LOCATION_LOC (insn), + ALL_REGS, GET_MODE (loc), + insn, vd); } if (insn == BB_END (bb)) @@ -684,6 +785,10 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd) recog_data.operand_type[i] = OP_INOUT; } + /* Apply changes to earlier DEBUG_INSNs if possible. */ + if (vd->n_debug_insn_changes) + note_uses (&PATTERN (insn), cprop_find_used_regs, vd); + /* For each earlyclobber operand, zap the value data. */ for (i = 0; i < n_ops; i++) if (recog_op_alt[i][alt].earlyclobber) @@ -871,12 +976,18 @@ copyprop_hardreg_forward (void) struct value_data *all_vd; basic_block bb; sbitmap visited; + bool analyze_called = false; all_vd = XNEWVEC (struct value_data, last_basic_block); visited = sbitmap_alloc (last_basic_block); sbitmap_zero (visited); + if (MAY_HAVE_DEBUG_STMTS) + debug_insn_changes_pool + = create_alloc_pool ("debug insn changes pool", + sizeof (struct queued_debug_insn_change), 256); + FOR_EACH_BB (bb) { SET_BIT (visited, bb->index); @@ -888,13 +999,57 @@ copyprop_hardreg_forward (void) if (single_pred_p (bb) && TEST_BIT (visited, single_pred (bb)->index) && ! (single_pred_edge (bb)->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))) - all_vd[bb->index] = all_vd[single_pred (bb)->index]; + { + all_vd[bb->index] = all_vd[single_pred (bb)->index]; + if (all_vd[bb->index].n_debug_insn_changes) + { + unsigned int regno; + + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + { + if (all_vd[bb->index].e[regno].debug_insn_changes) + { + all_vd[bb->index].e[regno].debug_insn_changes = NULL; + if (--all_vd[bb->index].n_debug_insn_changes == 0) + break; + } + } + } + } else init_value_data (all_vd + bb->index); copyprop_hardreg_forward_1 (bb, all_vd + bb->index); } + if (MAY_HAVE_DEBUG_STMTS) + { + FOR_EACH_BB (bb) + if (TEST_BIT (visited, bb->index) + && all_vd[bb->index].n_debug_insn_changes) + { + unsigned int regno; + bitmap live; + + if (!analyze_called) + { + df_analyze (); + analyze_called = true; + } + live = df_get_live_out (bb); + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (all_vd[bb->index].e[regno].debug_insn_changes) + { + if (REGNO_REG_SET_P (live, regno)) + apply_debug_insn_changes (all_vd + bb->index, regno); + if (all_vd[bb->index].n_debug_insn_changes == 0) + break; + } + } + + free_alloc_pool (debug_insn_changes_pool); + } + sbitmap_free (visited); free (all_vd); return 0; @@ -1026,6 +1181,7 @@ struct rtl_opt_pass pass_cprop_hardreg = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func | TODO_verify_rtl_sharing /* todo_flags_finish */ + TODO_dump_func | TODO_df_finish + | TODO_verify_rtl_sharing /* todo_flags_finish */ } }; |