for gcc/ChangeLog from Alexandre Oliva * df.h (enum debug_temp_where): New. (dead_debug_init, dead_debug_finish) Declare. (dead_debug_add, dead_debug_insert_temp): Declare. (struct dead_debug_use, struct dead_debug): Moved from... * df-problems.c: ... here. (df_set_unused_notes_for_mw): Bind debug uses of unused regno to a debug temp. (df_create_unused_note): Likewise. (df_set_dead_notes_for_mw): Move comment where it belongs. (dead_debug_init): Export. (dead_debug_reset_uses): New, factored out of... (dead_debug_finish): ...this. Export. (dead_debug_reset): Remove. (dead_debug_add): Export. (dead_debug_insert_before): Rename to... (dead_debug_insert_temp): ... this. Add where argument. Export. Locate stored value for BEFORE_WITH_VALUE. Avoid repeat inserts. Return insertion count. (df_note_bb_compute): Adjust. * dce.c (word_dce_process_block): Adjust dead debug uses. (dce_process_block): Likewise. Index: gcc/df-problems.c =================================================================== --- gcc/df-problems.c.orig 2011-06-03 11:41:26.507743096 -0300 +++ gcc/df-problems.c 2011-06-06 10:25:17.854030387 -0300 @@ -2842,25 +2842,6 @@ df_whole_mw_reg_unused_p (struct df_mw_h } -/* Node of a linked list of uses of dead REGs in debug insns. */ -struct dead_debug_use -{ - df_ref use; - struct dead_debug_use *next; -}; - -/* Linked list of the above, with a bitmap of the REGs in the - list. */ -struct dead_debug -{ - struct dead_debug_use *head; - bitmap used; - bitmap to_rescan; -}; - -static void dead_debug_reset (struct dead_debug *, unsigned int); - - /* Set the REG_UNUSED notes for the multiword hardreg defs in INSN based on the bits in LIVE. Do not generate notes for registers in artificial uses. DO_NOT_GEN is updated so that REG_DEAD notes are @@ -2886,7 +2867,7 @@ df_set_unused_notes_for_mw (rtx insn, st { unsigned int regno = mws->start_regno; df_set_note (REG_UNUSED, insn, mws->mw_reg); - dead_debug_reset (debug, regno); + dead_debug_insert_temp (debug, regno, insn, DEBUG_TEMP_AFTER_WITH_REG); #ifdef REG_DEAD_DEBUGGING df_print_note ("adding 1: ", insn, REG_NOTES (insn)); @@ -2901,7 +2882,7 @@ df_set_unused_notes_for_mw (rtx insn, st && !bitmap_bit_p (artificial_uses, r)) { df_set_note (REG_UNUSED, insn, regno_reg_rtx[r]); - dead_debug_reset (debug, r); + dead_debug_insert_temp (debug, r, insn, DEBUG_TEMP_AFTER_WITH_REG); #ifdef REG_DEAD_DEBUGGING df_print_note ("adding 2: ", insn, REG_NOTES (insn)); #endif @@ -2969,12 +2950,12 @@ df_set_dead_notes_for_mw (rtx insn, stru if (df_whole_mw_reg_dead_p (mws, live, artificial_uses, do_not_gen)) { - /* Add a dead note for the entire multi word register. */ if (is_debug) { *added_notes_p = true; return; } + /* Add a dead note for the entire multi word register. */ df_set_note (REG_DEAD, insn, mws->mw_reg); #ifdef REG_DEAD_DEBUGGING df_print_note ("adding 1: ", insn, REG_NOTES (insn)); @@ -3028,7 +3009,7 @@ df_create_unused_note (rtx insn, df_ref rtx reg = (DF_REF_LOC (def)) ? *DF_REF_REAL_LOC (def): DF_REF_REG (def); df_set_note (REG_UNUSED, insn, reg); - dead_debug_reset (debug, dregno); + dead_debug_insert_temp (debug, dregno, insn, DEBUG_TEMP_AFTER_WITH_REG); #ifdef REG_DEAD_DEBUGGING df_print_note ("adding 3: ", insn, REG_NOTES (insn)); #endif @@ -3039,7 +3020,7 @@ df_create_unused_note (rtx insn, df_ref /* Initialize DEBUG to an empty list, and clear USED, if given. */ -static inline void +void dead_debug_init (struct dead_debug *debug, bitmap used) { debug->head = NULL; @@ -3049,32 +3030,83 @@ dead_debug_init (struct dead_debug *debu bitmap_clear (used); } -/* Reset all debug insns with pending uses. Release the bitmap in it, - unless it is USED. USED must be the same bitmap passed to - dead_debug_init. */ -static inline void -dead_debug_finish (struct dead_debug *debug, bitmap used) +/* Reset all debug uses in HEAD, and clear DEBUG->to_rescan bits of + each reset insn. DEBUG is not otherwise modified. If HEAD is + DEBUG->head, DEBUG->head will be set to NULL at the end. + Otherwise, entries from DEBUG->head that pertain to reset insns + will be removed, and only then rescanned. */ + +static void +dead_debug_reset_uses (struct dead_debug *debug, struct dead_debug_use *head) { - struct dead_debug_use *head; - rtx insn = NULL; + bool got_head = (debug->head == head); + bitmap rescan; + struct dead_debug_use **tailp = &debug->head; + struct dead_debug_use *cur; + bitmap_iterator bi; + unsigned int uid; - if (debug->used != used) - BITMAP_FREE (debug->used); + if (got_head) + rescan = NULL; + else + rescan = BITMAP_ALLOC (NULL); - while ((head = debug->head)) + while (head) { + struct dead_debug_use *next = head->next; + rtx insn; + insn = DF_REF_INSN (head->use); - if (!head->next || DF_REF_INSN (head->next->use) != insn) + if (!next || DF_REF_INSN (next->use) != insn) { INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC (); - df_insn_rescan_debug_internal (insn); + if (got_head) + df_insn_rescan_debug_internal (insn); + else + bitmap_set_bit (rescan, INSN_UID (insn)); if (debug->to_rescan) bitmap_clear_bit (debug->to_rescan, INSN_UID (insn)); } - debug->head = head->next; XDELETE (head); + head = next; } + if (got_head) + { + debug->head = NULL; + return; + } + + while ((cur = *tailp)) + if (bitmap_bit_p (rescan, INSN_UID (DF_REF_INSN (cur->use)))) + { + *tailp = cur->next; + XDELETE (cur); + } + else + tailp = &cur->next; + + EXECUTE_IF_SET_IN_BITMAP (rescan, 0, uid, bi) + { + struct df_insn_info *insn_info = DF_INSN_UID_SAFE_GET (uid); + if (insn_info) + df_insn_rescan_debug_internal (insn_info->insn); + } + + BITMAP_FREE (rescan); +} + +/* Reset all debug insns with pending uses. Release the bitmap in it, + unless it is USED. USED must be the same bitmap passed to + dead_debug_init. */ +void +dead_debug_finish (struct dead_debug *debug, bitmap used) +{ + if (debug->used != used) + BITMAP_FREE (debug->used); + + dead_debug_reset_uses (debug, debug->head); + if (debug->to_rescan) { bitmap_iterator bi; @@ -3090,37 +3122,9 @@ dead_debug_finish (struct dead_debug *de } } -/* Reset DEBUG_INSNs with pending uses of DREGNO. */ -static void -dead_debug_reset (struct dead_debug *debug, unsigned int dregno) -{ - struct dead_debug_use **tailp = &debug->head; - struct dead_debug_use *cur; - rtx insn; - - if (!debug->used || !bitmap_clear_bit (debug->used, dregno)) - return; - - while ((cur = *tailp)) - { - if (DF_REF_REGNO (cur->use) == dregno) - { - *tailp = cur->next; - insn = DF_REF_INSN (cur->use); - INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC (); - if (debug->to_rescan == NULL) - debug->to_rescan = BITMAP_ALLOC (NULL); - bitmap_set_bit (debug->to_rescan, INSN_UID (insn)); - XDELETE (cur); - } - else - tailp = &(*tailp)->next; - } -} - /* Add USE to DEBUG. It must be a dead reference to UREGNO in a debug insn. Create a bitmap for DEBUG as needed. */ -static inline void +void dead_debug_add (struct dead_debug *debug, df_ref use, unsigned int uregno) { struct dead_debug_use *newddu = XNEW (struct dead_debug_use); @@ -3136,12 +3140,15 @@ dead_debug_add (struct dead_debug *debug } /* If UREGNO is referenced by any entry in DEBUG, emit a debug insn - before INSN that binds the REG to a debug temp, and replace all - uses of UREGNO in DEBUG with uses of the debug temp. INSN must be - the insn where UREGNO dies. */ -static inline void -dead_debug_insert_before (struct dead_debug *debug, unsigned int uregno, - rtx insn) + before or after INSN (depending on WHERE), that binds a debug temp + to the widest-mode use of UREGNO, if WHERE is _WITH_REG, or + _WITH_VALUE otherwise, and replace all uses of UREGNO in DEBUG with + uses of the debug temp. INSN must be where UREGNO dies, if WHERE + is DEAD_DEBUG_BEFORE_WITH_REG, or where it is set otherwise. + Return the number of debug insns emitted. */ +int +dead_debug_insert_temp (struct dead_debug *debug, unsigned int uregno, + rtx insn, enum debug_temp_where where) { struct dead_debug_use **tailp = &debug->head; struct dead_debug_use *cur; @@ -3152,7 +3159,7 @@ dead_debug_insert_before (struct dead_de rtx bind; if (!debug->used || !bitmap_clear_bit (debug->used, uregno)) - return; + return 0; /* Move all uses of uregno from debug->head to uses, setting mode to the widest referenced mode. */ @@ -3173,17 +3180,100 @@ dead_debug_insert_before (struct dead_de tailp = &(*tailp)->next; } - gcc_assert (reg); + if (!reg) + { + gcc_checking_assert (!uses); + return 0; + } + + gcc_checking_assert (uses); + + bind = reg; + if (where == DEBUG_TEMP_BEFORE_WITH_VALUE) + { + rtx set = single_set (insn); + rtx dest, src; + + if (set) + { + dest = SET_DEST (set); + src = SET_SRC (set); + if (GET_CODE (src) == CALL) + { + while (uses) + { + cur = uses->next; + XDELETE (uses); + uses = cur; + } + return 0; + } + } + else + set = NULL; + + if (!set) + bind = NULL; + else if (dest == reg) + bind = copy_rtx (src); + else if (REG_P (dest)) + { + if (REGNO (dest) != REGNO (reg)) + bind = NULL; + else + bind = lowpart_subreg (GET_MODE (reg), copy_rtx (src), + GET_MODE (dest)); + } + else if (GET_CODE (dest) == SUBREG) + { + if (REGNO (SUBREG_REG (dest)) != REGNO (reg)) + bind = NULL; + else if (!subreg_lowpart_p (dest)) + bind = NULL; + else if (REGNO (reg) < FIRST_PSEUDO_REGISTER + && (hard_regno_nregs[REGNO (reg)][GET_MODE (reg)] + == hard_regno_nregs[REGNO (reg)][GET_MODE (dest)])) + bind = NULL; + else + bind = lowpart_subreg (GET_MODE (reg), copy_rtx (src), + GET_MODE (dest)); + } + else + bind = NULL; + + if (!bind) + { + dead_debug_reset_uses (debug, uses); + return 0; + } + } + + /* If there's a single (debug) use of an otherwise unused REG, and + the debug use is not part of a larger expression, then it + probably doesn't make sense to introduce a new debug temp. */ + if (where == DEBUG_TEMP_AFTER_WITH_REG && !uses->next) + { + rtx next = DF_REF_INSN (uses->use); + + if (DEBUG_INSN_P (next) && reg == INSN_VAR_LOCATION_LOC (next)) + { + XDELETE (uses); + return 0; + } + } /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL). */ dval = make_debug_expr_from_rtl (reg); /* Emit a debug bind insn before the insn in which reg dies. */ bind = gen_rtx_VAR_LOCATION (GET_MODE (reg), - DEBUG_EXPR_TREE_DECL (dval), reg, + DEBUG_EXPR_TREE_DECL (dval), bind, VAR_INIT_STATUS_INITIALIZED); - bind = emit_debug_insn_before (bind, insn); + if (where == DEBUG_TEMP_AFTER_WITH_REG) + bind = emit_debug_insn_after (bind, insn); + else + bind = emit_debug_insn_before (bind, insn); df_insn_rescan (bind); /* Adjust all uses. */ @@ -3201,6 +3291,8 @@ dead_debug_insert_before (struct dead_de uses = cur->next; XDELETE (cur); } + + return 1; } /* Recompute the REG_DEAD and REG_UNUSED notes and compute register @@ -3395,7 +3487,8 @@ df_note_bb_compute (unsigned int bb_inde break; } else - dead_debug_insert_before (&debug, uregno, insn); + dead_debug_insert_temp (&debug, uregno, insn, + DEBUG_TEMP_BEFORE_WITH_REG); if ( (!(DF_REF_FLAGS (use) & (DF_REF_MW_HARDREG | DF_REF_READ_WRITE))) Index: gcc/dce.c =================================================================== --- gcc/dce.c.orig 2011-06-06 10:24:15.683249129 -0300 +++ gcc/dce.c 2011-06-06 10:25:17.919030159 -0300 @@ -807,6 +807,7 @@ word_dce_process_block (basic_block bb, bitmap local_live = BITMAP_ALLOC (&dce_tmp_bitmap_obstack); rtx insn; bool block_changed; + struct dead_debug debug; if (redo_out) { @@ -828,11 +829,24 @@ word_dce_process_block (basic_block bb, } bitmap_copy (local_live, DF_WORD_LR_OUT (bb)); + dead_debug_init (&debug, NULL); FOR_BB_INSNS_REVERSE (bb, insn) - if (NONDEBUG_INSN_P (insn)) + if (DEBUG_INSN_P (insn)) + { + df_ref *use_rec; + for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++) + if (DF_REF_REGNO (*use_rec) >= FIRST_PSEUDO_REGISTER + && (GET_MODE_SIZE (GET_MODE (DF_REF_REAL_REG (*use_rec))) + == 2 * UNITS_PER_WORD) + && !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (*use_rec)) + && !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (*use_rec) + 1)) + dead_debug_add (&debug, *use_rec, DF_REF_REGNO (*use_rec)); + } + else if (INSN_P (insn)) { bool any_changed; + /* No matter if the instruction is needed or not, we remove any regno in the defs from the live set. */ any_changed = df_word_lr_simulate_defs (insn, local_live); @@ -844,6 +858,15 @@ word_dce_process_block (basic_block bb, if (marked_insn_p (insn)) df_word_lr_simulate_uses (insn, local_live); + if (debug.used && !bitmap_empty_p (debug.used)) + { + df_ref *def_rec; + + for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++) + dead_debug_insert_temp (&debug, DF_REF_REGNO (*def_rec), insn, + DEBUG_TEMP_BEFORE_WITH_VALUE); + } + if (dump_file) { fprintf (dump_file, "finished processing insn %d live out = ", @@ -856,6 +879,7 @@ word_dce_process_block (basic_block bb, if (block_changed) bitmap_copy (DF_WORD_LR_IN (bb), local_live); + dead_debug_finish (&debug, NULL); BITMAP_FREE (local_live); return block_changed; } @@ -873,6 +897,7 @@ dce_process_block (basic_block bb, bool rtx insn; bool block_changed; df_ref *def_rec; + struct dead_debug debug; if (redo_out) { @@ -896,22 +921,36 @@ dce_process_block (basic_block bb, bool bitmap_copy (local_live, DF_LR_OUT (bb)); df_simulate_initialize_backwards (bb, local_live); + dead_debug_init (&debug, NULL); FOR_BB_INSNS_REVERSE (bb, insn) - if (INSN_P (insn)) + if (DEBUG_INSN_P (insn)) + { + df_ref *use_rec; + for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++) + if (!bitmap_bit_p (local_live, DF_REF_REGNO (*use_rec)) + && !bitmap_bit_p (au, DF_REF_REGNO (*use_rec))) + dead_debug_add (&debug, *use_rec, DF_REF_REGNO (*use_rec)); + } + else if (INSN_P (insn)) { bool needed = marked_insn_p (insn); /* The insn is needed if there is someone who uses the output. */ if (!needed) for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++) - if (bitmap_bit_p (local_live, DF_REF_REGNO (*def_rec)) - || bitmap_bit_p (au, DF_REF_REGNO (*def_rec))) - { - needed = true; - mark_insn (insn, true); - break; - } + { + dead_debug_insert_temp (&debug, DF_REF_REGNO (*def_rec), insn, + DEBUG_TEMP_BEFORE_WITH_VALUE); + + if (bitmap_bit_p (local_live, DF_REF_REGNO (*def_rec)) + || bitmap_bit_p (au, DF_REF_REGNO (*def_rec))) + { + needed = true; + mark_insn (insn, true); + break; + } + } /* No matter if the instruction is needed or not, we remove any regno in the defs from the live set. */ @@ -923,6 +962,7 @@ dce_process_block (basic_block bb, bool df_simulate_uses (insn, local_live); } + dead_debug_finish (&debug, NULL); df_simulate_finalize_backwards (bb, local_live); block_changed = !bitmap_equal_p (local_live, DF_LR_IN (bb)); Index: gcc/df.h =================================================================== --- gcc/df.h.orig 2011-06-03 11:41:26.946741443 -0300 +++ gcc/df.h 2011-06-06 10:25:17.981029941 -0300 @@ -1101,4 +1101,35 @@ extern void union_defs (df_ref, struct w unsigned int *used, struct web_entry *, bool (*fun) (struct web_entry *, struct web_entry *)); +/* Debug uses of dead regs. */ + +/* Node of a linked list of uses of dead REGs in debug insns. */ +struct dead_debug_use +{ + df_ref use; + struct dead_debug_use *next; +}; + +/* Linked list of the above, with a bitmap of the REGs in the + list. */ +struct dead_debug +{ + struct dead_debug_use *head; + bitmap used; + bitmap to_rescan; +}; + +enum debug_temp_where + { + DEBUG_TEMP_BEFORE_WITH_REG = -1, + DEBUG_TEMP_BEFORE_WITH_VALUE = 0, + DEBUG_TEMP_AFTER_WITH_REG = 1 + }; + +void dead_debug_init (struct dead_debug *, bitmap); +void dead_debug_finish (struct dead_debug *, bitmap); +void dead_debug_add (struct dead_debug *, df_ref, unsigned int); +int dead_debug_insert_temp (struct dead_debug *, unsigned int, rtx, + enum debug_temp_where); + #endif /* GCC_DF_H */