https://gcc.gnu.org/g:96c7ea34796ff0c661209c4fa4caebb78ec3428f
commit 96c7ea34796ff0c661209c4fa4caebb78ec3428f Author: Ondřej Machota <ondrejmach...@gmail.com> Date: Sun Sep 29 22:17:46 2024 +0200 rtl-ssa: dce fix mark compile and sweep sketch Diff: --- gcc/dce.cc | 1658 +++++++++++++++++++++++++++++------------------------------- 1 file changed, 807 insertions(+), 851 deletions(-) diff --git a/gcc/dce.cc b/gcc/dce.cc index f59bc6c6ffa2..cde7d7f3c83d 100644 --- a/gcc/dce.cc +++ b/gcc/dce.cc @@ -30,7 +30,7 @@ along with GCC; see the file COPYING3. If not see #include "rtl-ssa.h" #include "memmodel.h" #include "tm_p.h" -#include "emit-rtl.h" /* FIXME: Can go away once crtl is moved to rtl.h. */ +#include "emit-rtl.h" /* FIXME: Can go away once crtl is moved to rtl.h. */ #include "cfgrtl.h" #include "cfgbuild.h" #include "cfgcleanup.h" @@ -42,7 +42,6 @@ along with GCC; see the file COPYING3. If not see using namespace rtl_ssa; - /* ------------------------------------------------------------------------- Core mark/delete routines ------------------------------------------------------------------------- */ @@ -65,57 +64,57 @@ static sbitmap marked; static bitmap_obstack dce_blocks_bitmap_obstack; static bitmap_obstack dce_tmp_bitmap_obstack; -static bool find_call_stack_args (rtx_call_insn *, bool, bool, bitmap); +static bool find_call_stack_args(rtx_call_insn *, bool, bool, bitmap); /* A subroutine for which BODY is part of the instruction being tested; either the top-level pattern, or an element of a PARALLEL. The instruction is known not to be a bare USE or CLOBBER. */ static bool -deletable_insn_p_1 (rtx body) +deletable_insn_p_1(rtx body) { - switch (GET_CODE (body)) - { - case PREFETCH: - case TRAP_IF: - /* The UNSPEC case was added here because the ia-64 claims that - USEs do not work after reload and generates UNSPECS rather - than USEs. Since dce is run after reload we need to avoid - deleting these even if they are dead. If it turns out that - USEs really do work after reload, the ia-64 should be - changed, and the UNSPEC case can be removed. */ - case UNSPEC: - return false; + switch (GET_CODE(body)) + { + case PREFETCH: + case TRAP_IF: + /* The UNSPEC case was added here because the ia-64 claims that + USEs do not work after reload and generates UNSPECS rather + than USEs. Since dce is run after reload we need to avoid + deleting these even if they are dead. If it turns out that + USEs really do work after reload, the ia-64 should be + changed, and the UNSPEC case can be removed. */ + case UNSPEC: + return false; - default: - return !volatile_refs_p (body); - } + default: + return !volatile_refs_p(body); + } } /* Don't delete calls that may throw if we cannot do so. */ static bool -can_delete_call (rtx_insn *insn) +can_delete_call(rtx_insn *insn) { if (cfun->can_delete_dead_exceptions && can_alter_cfg) return true; - if (!insn_nothrow_p (insn)) + if (!insn_nothrow_p(insn)) return false; if (can_alter_cfg) return true; /* If we can't alter cfg, even when the call can't throw exceptions, it might have EDGE_ABNORMAL_CALL edges and so we shouldn't delete such calls. */ - gcc_assert (CALL_P (insn)); - if (BLOCK_FOR_INSN (insn) && BB_END (BLOCK_FOR_INSN (insn)) == insn) - { - edge e; - edge_iterator ei; - - FOR_EACH_EDGE (e, ei, BLOCK_FOR_INSN (insn)->succs) - if ((e->flags & EDGE_ABNORMAL_CALL) != 0) - return false; - } + gcc_assert(CALL_P(insn)); + if (BLOCK_FOR_INSN(insn) && BB_END(BLOCK_FOR_INSN(insn)) == insn) + { + edge e; + edge_iterator ei; + + FOR_EACH_EDGE(e, ei, BLOCK_FOR_INSN(insn)->succs) + if ((e->flags & EDGE_ABNORMAL_CALL) != 0) + return false; + } return true; } @@ -123,175 +122,156 @@ can_delete_call (rtx_insn *insn) the DCE pass. */ static bool -deletable_insn_p (rtx_insn *insn, bool fast, bitmap arg_stores) +deletable_insn_p(rtx_insn *insn, bool fast, bitmap arg_stores) { rtx body, x; int i; df_ref def; - if (CALL_P (insn) + if (CALL_P(insn) /* We cannot delete calls inside of the recursive dce because - this may cause basic blocks to be deleted and this messes up - the rest of the stack of optimization passes. */ + this may cause basic blocks to be deleted and this messes up + the rest of the stack of optimization passes. */ && (!df_in_progress) /* We cannot delete pure or const sibling calls because it is - hard to see the result. */ - && (!SIBLING_CALL_P (insn)) + hard to see the result. */ + && (!SIBLING_CALL_P(insn)) /* We can delete dead const or pure calls as long as they do not infinite loop. */ - && (RTL_CONST_OR_PURE_CALL_P (insn) - && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)) + && (RTL_CONST_OR_PURE_CALL_P(insn) && !RTL_LOOPING_CONST_OR_PURE_CALL_P(insn)) /* Don't delete calls that may throw if we cannot do so. */ - && can_delete_call (insn)) - return find_call_stack_args (as_a <rtx_call_insn *> (insn), false, - fast, arg_stores); + && can_delete_call(insn)) + return find_call_stack_args(as_a<rtx_call_insn *>(insn), false, + fast, arg_stores); /* Don't delete jumps, notes and the like. */ - if (!NONJUMP_INSN_P (insn)) + if (!NONJUMP_INSN_P(insn)) return false; /* Don't delete insns that may throw if we cannot do so. */ - if (!(cfun->can_delete_dead_exceptions && can_alter_cfg) - && !insn_nothrow_p (insn)) + if (!(cfun->can_delete_dead_exceptions && can_alter_cfg) && !insn_nothrow_p(insn)) return false; /* If INSN sets a global_reg, leave it untouched. */ - FOR_EACH_INSN_DEF (def, insn) - if (HARD_REGISTER_NUM_P (DF_REF_REGNO (def)) - && global_regs[DF_REF_REGNO (def)]) - return false; - /* Initialization of pseudo PIC register should never be removed. */ - else if (DF_REF_REG (def) == pic_offset_table_rtx - && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER) - return false; + FOR_EACH_INSN_DEF(def, insn) + if (HARD_REGISTER_NUM_P(DF_REF_REGNO(def)) && global_regs[DF_REF_REGNO(def)]) + return false; + /* Initialization of pseudo PIC register should never be removed. */ + else if (DF_REF_REG(def) == pic_offset_table_rtx && REGNO(pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER) + return false; /* Callee-save restores are needed. */ - if (RTX_FRAME_RELATED_P (insn) - && crtl->shrink_wrapped_separate - && find_reg_note (insn, REG_CFA_RESTORE, NULL)) + if (RTX_FRAME_RELATED_P(insn) && crtl->shrink_wrapped_separate && find_reg_note(insn, REG_CFA_RESTORE, NULL)) return false; - body = PATTERN (insn); - switch (GET_CODE (body)) + body = PATTERN(insn); + switch (GET_CODE(body)) + { + case USE: + case VAR_LOCATION: + return false; + + case CLOBBER: + if (fast) { - case USE: - case VAR_LOCATION: + /* A CLOBBER of a dead pseudo register serves no purpose. + That is not necessarily true for hard registers until + after reload. */ + x = XEXP(body, 0); + return REG_P(x) && (!HARD_REGISTER_P(x) || reload_completed); + } + else + /* Because of the way that use-def chains are built, it is not + possible to tell if the clobber is dead because it can + never be the target of a use-def chain. */ return false; - case CLOBBER: - if (fast) - { - /* A CLOBBER of a dead pseudo register serves no purpose. - That is not necessarily true for hard registers until - after reload. */ - x = XEXP (body, 0); - return REG_P (x) && (!HARD_REGISTER_P (x) || reload_completed); - } - else - /* Because of the way that use-def chains are built, it is not - possible to tell if the clobber is dead because it can - never be the target of a use-def chain. */ - return false; - - case PARALLEL: - for (i = XVECLEN (body, 0) - 1; i >= 0; i--) - if (!deletable_insn_p_1 (XVECEXP (body, 0, i))) - return false; - return true; - - default: - return deletable_insn_p_1 (body); - } -} + case PARALLEL: + for (i = XVECLEN(body, 0) - 1; i >= 0; i--) + if (!deletable_insn_p_1(XVECEXP(body, 0, i))) + return false; + return true; + default: + return deletable_insn_p_1(body); + } +} /* Return true if INSN has been marked as needed. */ static inline int -marked_insn_p (rtx_insn *insn) +marked_insn_p(rtx_insn *insn) { /* Artificial defs are always needed and they do not have an insn. We should never see them here. */ - gcc_assert (insn); - return bitmap_bit_p (marked, INSN_UID (insn)); + gcc_assert(insn); + return bitmap_bit_p(marked, INSN_UID(insn)); } - /* If INSN has not yet been marked as needed, mark it now, and add it to the worklist. */ static void -mark_insn (rtx_insn *insn, bool fast) +mark_insn(rtx_insn *insn, bool fast) { - if (!marked_insn_p (insn)) - { - if (!fast) - worklist.safe_push (insn); - bitmap_set_bit (marked, INSN_UID (insn)); - if (dump_file) - fprintf (dump_file, " Adding insn %d to worklist\n", INSN_UID (insn)); - if (CALL_P (insn) - && !df_in_progress - && !SIBLING_CALL_P (insn) - && (RTL_CONST_OR_PURE_CALL_P (insn) - && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)) - && can_delete_call (insn)) - find_call_stack_args (as_a <rtx_call_insn *> (insn), true, fast, NULL); - } + if (!marked_insn_p(insn)) + { + if (!fast) + worklist.safe_push(insn); + bitmap_set_bit(marked, INSN_UID(insn)); + if (dump_file) + fprintf(dump_file, " Adding insn %d to worklist\n", INSN_UID(insn)); + if (CALL_P(insn) && !df_in_progress && !SIBLING_CALL_P(insn) && (RTL_CONST_OR_PURE_CALL_P(insn) && !RTL_LOOPING_CONST_OR_PURE_CALL_P(insn)) && can_delete_call(insn)) + find_call_stack_args(as_a<rtx_call_insn *>(insn), true, fast, NULL); + } } - /* A note_stores callback used by mark_nonreg_stores. DATA is the instruction containing DEST. */ static void -mark_nonreg_stores_1 (rtx dest, const_rtx pattern, void *data) +mark_nonreg_stores_1(rtx dest, const_rtx pattern, void *data) { - if (GET_CODE (pattern) != CLOBBER && !REG_P (dest)) - mark_insn ((rtx_insn *) data, true); + if (GET_CODE(pattern) != CLOBBER && !REG_P(dest)) + mark_insn((rtx_insn *)data, true); } - /* A note_stores callback used by mark_nonreg_stores. DATA is the instruction containing DEST. */ static void -mark_nonreg_stores_2 (rtx dest, const_rtx pattern, void *data) +mark_nonreg_stores_2(rtx dest, const_rtx pattern, void *data) { - if (GET_CODE (pattern) != CLOBBER && !REG_P (dest)) - mark_insn ((rtx_insn *) data, false); + if (GET_CODE(pattern) != CLOBBER && !REG_P(dest)) + mark_insn((rtx_insn *)data, false); } - /* Mark INSN if it stores to a non-register destination. */ static void -mark_nonreg_stores (rtx_insn *insn, bool fast) +mark_nonreg_stores(rtx_insn *insn, bool fast) { if (fast) - note_stores (insn, mark_nonreg_stores_1, insn); + note_stores(insn, mark_nonreg_stores_1, insn); else - note_stores (insn, mark_nonreg_stores_2, insn); + note_stores(insn, mark_nonreg_stores_2, insn); } - /* Return true if a store to SIZE bytes, starting OFF bytes from stack pointer, is a call argument store, and clear corresponding bits from SP_BYTES bitmap if it is. */ static bool -check_argument_store (HOST_WIDE_INT size, HOST_WIDE_INT off, - HOST_WIDE_INT min_sp_off, HOST_WIDE_INT max_sp_off, - bitmap sp_bytes) +check_argument_store(HOST_WIDE_INT size, HOST_WIDE_INT off, + HOST_WIDE_INT min_sp_off, HOST_WIDE_INT max_sp_off, + bitmap sp_bytes) { HOST_WIDE_INT byte; for (byte = off; byte < off + size; byte++) - { - if (byte < min_sp_off - || byte >= max_sp_off - || !bitmap_clear_bit (sp_bytes, byte - min_sp_off)) - return false; - } + { + if (byte < min_sp_off || byte >= max_sp_off || !bitmap_clear_bit(sp_bytes, byte - min_sp_off)) + return false; + } return true; } @@ -301,55 +281,52 @@ check_argument_store (HOST_WIDE_INT size, HOST_WIDE_INT off, INTTYPE_MINUMUM (HOST_WIDE_INT). */ static HOST_WIDE_INT -sp_based_mem_offset (rtx_call_insn *call_insn, const_rtx mem, bool fast) +sp_based_mem_offset(rtx_call_insn *call_insn, const_rtx mem, bool fast) { HOST_WIDE_INT off = 0; - rtx addr = XEXP (mem, 0); - if (GET_CODE (addr) == PLUS - && REG_P (XEXP (addr, 0)) - && CONST_INT_P (XEXP (addr, 1))) - { - off = INTVAL (XEXP (addr, 1)); - addr = XEXP (addr, 0); - } + rtx addr = XEXP(mem, 0); + if (GET_CODE(addr) == PLUS && REG_P(XEXP(addr, 0)) && CONST_INT_P(XEXP(addr, 1))) + { + off = INTVAL(XEXP(addr, 1)); + addr = XEXP(addr, 0); + } if (addr == stack_pointer_rtx) return off; - if (!REG_P (addr) || fast) - return INTTYPE_MINIMUM (HOST_WIDE_INT); + if (!REG_P(addr) || fast) + return INTTYPE_MINIMUM(HOST_WIDE_INT); /* If not fast, use chains to see if addr wasn't set to sp + offset. */ df_ref use; - FOR_EACH_INSN_USE (use, call_insn) - if (rtx_equal_p (addr, DF_REF_REG (use))) + FOR_EACH_INSN_USE(use, call_insn) + if (rtx_equal_p(addr, DF_REF_REG(use))) break; if (use == NULL) - return INTTYPE_MINIMUM (HOST_WIDE_INT); + return INTTYPE_MINIMUM(HOST_WIDE_INT); struct df_link *defs; - for (defs = DF_REF_CHAIN (use); defs; defs = defs->next) - if (! DF_REF_IS_ARTIFICIAL (defs->ref)) + for (defs = DF_REF_CHAIN(use); defs; defs = defs->next) + if (!DF_REF_IS_ARTIFICIAL(defs->ref)) break; if (defs == NULL) - return INTTYPE_MINIMUM (HOST_WIDE_INT); + return INTTYPE_MINIMUM(HOST_WIDE_INT); - rtx set = single_set (DF_REF_INSN (defs->ref)); + rtx set = single_set(DF_REF_INSN(defs->ref)); if (!set) - return INTTYPE_MINIMUM (HOST_WIDE_INT); + return INTTYPE_MINIMUM(HOST_WIDE_INT); - if (GET_CODE (SET_SRC (set)) != PLUS - || XEXP (SET_SRC (set), 0) != stack_pointer_rtx - || !CONST_INT_P (XEXP (SET_SRC (set), 1))) - return INTTYPE_MINIMUM (HOST_WIDE_INT); + if (GET_CODE(SET_SRC(set)) != PLUS || XEXP(SET_SRC(set), 0) != stack_pointer_rtx || !CONST_INT_P(XEXP(SET_SRC(set), 1))) + return INTTYPE_MINIMUM(HOST_WIDE_INT); - off += INTVAL (XEXP (SET_SRC (set), 1)); + off += INTVAL(XEXP(SET_SRC(set), 1)); return off; } /* Data for check_argument_load called via note_uses. */ -struct check_argument_load_data { +struct check_argument_load_data +{ bitmap sp_bytes; HOST_WIDE_INT min_sp_off, max_sp_off; rtx_call_insn *call_insn; @@ -362,32 +339,27 @@ struct check_argument_load_data { and store to the argument slot, set LOAD_FOUND if any is found. */ static void -check_argument_load (rtx *loc, void *data) +check_argument_load(rtx *loc, void *data) { - struct check_argument_load_data *d - = (struct check_argument_load_data *) data; + struct check_argument_load_data *d = (struct check_argument_load_data *)data; subrtx_iterator::array_type array; - FOR_EACH_SUBRTX (iter, array, *loc, NONCONST) + FOR_EACH_SUBRTX(iter, array, *loc, NONCONST) + { + const_rtx mem = *iter; + HOST_WIDE_INT size; + if (MEM_P(mem) && MEM_SIZE_KNOWN_P(mem) && MEM_SIZE(mem).is_constant(&size)) { - const_rtx mem = *iter; - HOST_WIDE_INT size; - if (MEM_P (mem) - && MEM_SIZE_KNOWN_P (mem) - && MEM_SIZE (mem).is_constant (&size)) - { - HOST_WIDE_INT off = sp_based_mem_offset (d->call_insn, mem, d->fast); - if (off != INTTYPE_MINIMUM (HOST_WIDE_INT) - && off < d->max_sp_off - && off + size > d->min_sp_off) - for (HOST_WIDE_INT byte = MAX (off, d->min_sp_off); - byte < MIN (off + size, d->max_sp_off); byte++) - if (bitmap_bit_p (d->sp_bytes, byte - d->min_sp_off)) - { - d->load_found = true; - return; - } - } + HOST_WIDE_INT off = sp_based_mem_offset(d->call_insn, mem, d->fast); + if (off != INTTYPE_MINIMUM(HOST_WIDE_INT) && off < d->max_sp_off && off + size > d->min_sp_off) + for (HOST_WIDE_INT byte = MAX(off, d->min_sp_off); + byte < MIN(off + size, d->max_sp_off); byte++) + if (bitmap_bit_p(d->sp_bytes, byte - d->min_sp_off)) + { + d->load_found = true; + return; + } } + } } /* Try to find all stack stores of CALL_INSN arguments if @@ -398,8 +370,8 @@ check_argument_load (rtx *loc, void *data) going to be marked called again with DO_MARK true. */ static bool -find_call_stack_args (rtx_call_insn *call_insn, bool do_mark, bool fast, - bitmap arg_stores) +find_call_stack_args(rtx_call_insn *call_insn, bool do_mark, bool fast, + bitmap arg_stores) { rtx p; rtx_insn *insn, *prev_insn; @@ -407,474 +379,457 @@ find_call_stack_args (rtx_call_insn *call_insn, bool do_mark, bool fast, HOST_WIDE_INT min_sp_off, max_sp_off; bitmap sp_bytes; - gcc_assert (CALL_P (call_insn)); + gcc_assert(CALL_P(call_insn)); if (!ACCUMULATE_OUTGOING_ARGS) return true; if (!do_mark) - { - gcc_assert (arg_stores); - bitmap_clear (arg_stores); - } + { + gcc_assert(arg_stores); + bitmap_clear(arg_stores); + } - min_sp_off = INTTYPE_MAXIMUM (HOST_WIDE_INT); + min_sp_off = INTTYPE_MAXIMUM(HOST_WIDE_INT); max_sp_off = 0; /* First determine the minimum and maximum offset from sp for stored arguments. */ - for (p = CALL_INSN_FUNCTION_USAGE (call_insn); p; p = XEXP (p, 1)) - if (GET_CODE (XEXP (p, 0)) == USE - && MEM_P (XEXP (XEXP (p, 0), 0))) - { - rtx mem = XEXP (XEXP (p, 0), 0); - HOST_WIDE_INT size; - if (!MEM_SIZE_KNOWN_P (mem) || !MEM_SIZE (mem).is_constant (&size)) - return false; - HOST_WIDE_INT off = sp_based_mem_offset (call_insn, mem, fast); - if (off == INTTYPE_MINIMUM (HOST_WIDE_INT)) - return false; - min_sp_off = MIN (min_sp_off, off); - max_sp_off = MAX (max_sp_off, off + size); - } + for (p = CALL_INSN_FUNCTION_USAGE(call_insn); p; p = XEXP(p, 1)) + if (GET_CODE(XEXP(p, 0)) == USE && MEM_P(XEXP(XEXP(p, 0), 0))) + { + rtx mem = XEXP(XEXP(p, 0), 0); + HOST_WIDE_INT size; + if (!MEM_SIZE_KNOWN_P(mem) || !MEM_SIZE(mem).is_constant(&size)) + return false; + HOST_WIDE_INT off = sp_based_mem_offset(call_insn, mem, fast); + if (off == INTTYPE_MINIMUM(HOST_WIDE_INT)) + return false; + min_sp_off = MIN(min_sp_off, off); + max_sp_off = MAX(max_sp_off, off + size); + } if (min_sp_off >= max_sp_off) return true; - sp_bytes = BITMAP_ALLOC (NULL); + sp_bytes = BITMAP_ALLOC(NULL); /* Set bits in SP_BYTES bitmap for bytes relative to sp + min_sp_off which contain arguments. Checking has been done in the previous loop. */ - for (p = CALL_INSN_FUNCTION_USAGE (call_insn); p; p = XEXP (p, 1)) - if (GET_CODE (XEXP (p, 0)) == USE - && MEM_P (XEXP (XEXP (p, 0), 0))) - { - rtx mem = XEXP (XEXP (p, 0), 0); - /* Checked in the previous iteration. */ - HOST_WIDE_INT size = MEM_SIZE (mem).to_constant (); - HOST_WIDE_INT off = sp_based_mem_offset (call_insn, mem, fast); - gcc_checking_assert (off != INTTYPE_MINIMUM (HOST_WIDE_INT)); - for (HOST_WIDE_INT byte = off; byte < off + size; byte++) - if (!bitmap_set_bit (sp_bytes, byte - min_sp_off)) - gcc_unreachable (); - } + for (p = CALL_INSN_FUNCTION_USAGE(call_insn); p; p = XEXP(p, 1)) + if (GET_CODE(XEXP(p, 0)) == USE && MEM_P(XEXP(XEXP(p, 0), 0))) + { + rtx mem = XEXP(XEXP(p, 0), 0); + /* Checked in the previous iteration. */ + HOST_WIDE_INT size = MEM_SIZE(mem).to_constant(); + HOST_WIDE_INT off = sp_based_mem_offset(call_insn, mem, fast); + gcc_checking_assert(off != INTTYPE_MINIMUM(HOST_WIDE_INT)); + for (HOST_WIDE_INT byte = off; byte < off + size; byte++) + if (!bitmap_set_bit(sp_bytes, byte - min_sp_off)) + gcc_unreachable(); + } /* Walk backwards, looking for argument stores. The search stops when seeing another call, sp adjustment, memory store other than argument store or a read from an argument stack slot. */ - struct check_argument_load_data data - = { sp_bytes, min_sp_off, max_sp_off, call_insn, fast, false }; + struct check_argument_load_data data = {sp_bytes, min_sp_off, max_sp_off, call_insn, fast, false}; ret = false; - for (insn = PREV_INSN (call_insn); insn; insn = prev_insn) - { - if (insn == BB_HEAD (BLOCK_FOR_INSN (call_insn))) - prev_insn = NULL; - else - prev_insn = PREV_INSN (insn); - - if (CALL_P (insn)) - break; + for (insn = PREV_INSN(call_insn); insn; insn = prev_insn) + { + if (insn == BB_HEAD(BLOCK_FOR_INSN(call_insn))) + prev_insn = NULL; + else + prev_insn = PREV_INSN(insn); + + if (CALL_P(insn)) + break; - if (!NONDEBUG_INSN_P (insn)) - continue; + if (!NONDEBUG_INSN_P(insn)) + continue; - rtx set = single_set (insn); - if (!set || SET_DEST (set) == stack_pointer_rtx) - break; + rtx set = single_set(insn); + if (!set || SET_DEST(set) == stack_pointer_rtx) + break; - note_uses (&PATTERN (insn), check_argument_load, &data); - if (data.load_found) - break; + note_uses(&PATTERN(insn), check_argument_load, &data); + if (data.load_found) + break; - if (!MEM_P (SET_DEST (set))) - continue; + if (!MEM_P(SET_DEST(set))) + continue; - rtx mem = SET_DEST (set); - HOST_WIDE_INT off = sp_based_mem_offset (call_insn, mem, fast); - if (off == INTTYPE_MINIMUM (HOST_WIDE_INT)) - break; + rtx mem = SET_DEST(set); + HOST_WIDE_INT off = sp_based_mem_offset(call_insn, mem, fast); + if (off == INTTYPE_MINIMUM(HOST_WIDE_INT)) + break; - HOST_WIDE_INT size; - if (!MEM_SIZE_KNOWN_P (mem) - || !MEM_SIZE (mem).is_constant (&size) - || !check_argument_store (size, off, min_sp_off, - max_sp_off, sp_bytes)) - break; + HOST_WIDE_INT size; + if (!MEM_SIZE_KNOWN_P(mem) || !MEM_SIZE(mem).is_constant(&size) || !check_argument_store(size, off, min_sp_off, max_sp_off, sp_bytes)) + break; - if (!deletable_insn_p (insn, fast, NULL)) - break; + if (!deletable_insn_p(insn, fast, NULL)) + break; - if (do_mark) - mark_insn (insn, fast); - else - bitmap_set_bit (arg_stores, INSN_UID (insn)); + if (do_mark) + mark_insn(insn, fast); + else + bitmap_set_bit(arg_stores, INSN_UID(insn)); - if (bitmap_empty_p (sp_bytes)) - { - ret = true; - break; - } + if (bitmap_empty_p(sp_bytes)) + { + ret = true; + break; } + } - BITMAP_FREE (sp_bytes); + BITMAP_FREE(sp_bytes); if (!ret && arg_stores) - bitmap_clear (arg_stores); + bitmap_clear(arg_stores); return ret; } - /* Remove all REG_EQUAL and REG_EQUIV notes referring to the registers INSN writes to. */ static void -remove_reg_equal_equiv_notes_for_defs (rtx_insn *insn) +remove_reg_equal_equiv_notes_for_defs(rtx_insn *insn) { df_ref def; - FOR_EACH_INSN_DEF (def, insn) - remove_reg_equal_equiv_notes_for_regno (DF_REF_REGNO (def)); + FOR_EACH_INSN_DEF(def, insn) + remove_reg_equal_equiv_notes_for_regno(DF_REF_REGNO(def)); } /* Scan all BBs for debug insns and reset those that reference values defined in unmarked insns. */ static void -reset_unmarked_insns_debug_uses (void) +reset_unmarked_insns_debug_uses(void) { basic_block bb; rtx_insn *insn, *next; - FOR_EACH_BB_REVERSE_FN (bb, cfun) - FOR_BB_INSNS_REVERSE_SAFE (bb, insn, next) - if (DEBUG_INSN_P (insn)) - { - df_ref use; - - FOR_EACH_INSN_USE (use, insn) - { - struct df_link *defs; - for (defs = DF_REF_CHAIN (use); defs; defs = defs->next) - { - rtx_insn *ref_insn; - if (DF_REF_IS_ARTIFICIAL (defs->ref)) - continue; - ref_insn = DF_REF_INSN (defs->ref); - if (!marked_insn_p (ref_insn)) - break; - } - if (!defs) - continue; - /* ??? FIXME could we propagate the values assigned to - each of the DEFs? */ - INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC (); - df_insn_rescan_debug_internal (insn); - break; - } - } + FOR_EACH_BB_REVERSE_FN(bb, cfun) + FOR_BB_INSNS_REVERSE_SAFE(bb, insn, next) + if (DEBUG_INSN_P(insn)) + { + df_ref use; + + FOR_EACH_INSN_USE(use, insn) + { + struct df_link *defs; + for (defs = DF_REF_CHAIN(use); defs; defs = defs->next) + { + rtx_insn *ref_insn; + if (DF_REF_IS_ARTIFICIAL(defs->ref)) + continue; + ref_insn = DF_REF_INSN(defs->ref); + if (!marked_insn_p(ref_insn)) + break; + } + if (!defs) + continue; + /* ??? FIXME could we propagate the values assigned to + each of the DEFs? */ + INSN_VAR_LOCATION_LOC(insn) = gen_rtx_UNKNOWN_VAR_LOC(); + df_insn_rescan_debug_internal(insn); + break; + } + } } /* Delete every instruction that hasn't been marked. */ static void -delete_unmarked_insns (void) +delete_unmarked_insns(void) { basic_block bb; rtx_insn *insn, *next; bool must_clean = false; - FOR_EACH_BB_REVERSE_FN (bb, cfun) - FOR_BB_INSNS_REVERSE_SAFE (bb, insn, next) - if (NONDEBUG_INSN_P (insn)) - { - rtx turn_into_use = NULL_RTX; - - /* Always delete no-op moves. */ - if (noop_move_p (insn) - /* Unless the no-op move can throw and we are not allowed - to alter cfg. */ - && (!cfun->can_throw_non_call_exceptions - || (cfun->can_delete_dead_exceptions && can_alter_cfg) - || insn_nothrow_p (insn))) - { - if (RTX_FRAME_RELATED_P (insn)) - turn_into_use - = find_reg_note (insn, REG_CFA_RESTORE, NULL); - if (turn_into_use && REG_P (XEXP (turn_into_use, 0))) - turn_into_use = XEXP (turn_into_use, 0); - else - turn_into_use = NULL_RTX; - } - - /* Otherwise rely only on the DCE algorithm. */ - else if (marked_insn_p (insn)) - continue; - - /* Beware that reaching a dbg counter limit here can result - in miscompiled file. This occurs when a group of insns - must be deleted together, typically because the kept insn - depends on the output from the deleted insn. Deleting - this insns in reverse order (both at the bb level and - when looking at the blocks) minimizes this, but does not - eliminate it, since it is possible for the using insn to - be top of a block and the producer to be at the bottom of - the block. However, in most cases this will only result - in an uninitialized use of an insn that is dead anyway. - - However, there is one rare case that will cause a - miscompile: deletion of non-looping pure and constant - calls on a machine where ACCUMULATE_OUTGOING_ARGS is true. - In this case it is possible to remove the call, but leave - the argument pushes to the stack. Because of the changes - to the stack pointer, this will almost always lead to a - miscompile. */ - if (!dbg_cnt (dce)) - continue; - - if (dump_file) - fprintf (dump_file, "DCE: Deleting insn %d\n", INSN_UID (insn)); - - /* Before we delete the insn we have to remove the REG_EQUAL notes - for the destination regs in order to avoid dangling notes. */ - remove_reg_equal_equiv_notes_for_defs (insn); - - if (turn_into_use) - { - /* Don't remove frame related noop moves if they cary - REG_CFA_RESTORE note, while we don't need to emit any code, - we need it to emit the CFI restore note. */ - PATTERN (insn) - = gen_rtx_USE (GET_MODE (turn_into_use), turn_into_use); - INSN_CODE (insn) = -1; - df_insn_rescan (insn); - } - else - /* Now delete the insn. */ - must_clean |= delete_insn_and_edges (insn); - } + FOR_EACH_BB_REVERSE_FN(bb, cfun) + FOR_BB_INSNS_REVERSE_SAFE(bb, insn, next) + if (NONDEBUG_INSN_P(insn)) + { + rtx turn_into_use = NULL_RTX; + + /* Always delete no-op moves. */ + if (noop_move_p(insn) + /* Unless the no-op move can throw and we are not allowed + to alter cfg. */ + && (!cfun->can_throw_non_call_exceptions || (cfun->can_delete_dead_exceptions && can_alter_cfg) || insn_nothrow_p(insn))) + { + if (RTX_FRAME_RELATED_P(insn)) + turn_into_use = find_reg_note(insn, REG_CFA_RESTORE, NULL); + if (turn_into_use && REG_P(XEXP(turn_into_use, 0))) + turn_into_use = XEXP(turn_into_use, 0); + else + turn_into_use = NULL_RTX; + } - /* Deleted a pure or const call. */ - if (must_clean) + /* Otherwise rely only on the DCE algorithm. */ + else if (marked_insn_p(insn)) + continue; + + /* Beware that reaching a dbg counter limit here can result + in miscompiled file. This occurs when a group of insns + must be deleted together, typically because the kept insn + depends on the output from the deleted insn. Deleting + this insns in reverse order (both at the bb level and + when looking at the blocks) minimizes this, but does not + eliminate it, since it is possible for the using insn to + be top of a block and the producer to be at the bottom of + the block. However, in most cases this will only result + in an uninitialized use of an insn that is dead anyway. + + However, there is one rare case that will cause a + miscompile: deletion of non-looping pure and constant + calls on a machine where ACCUMULATE_OUTGOING_ARGS is true. + In this case it is possible to remove the call, but leave + the argument pushes to the stack. Because of the changes + to the stack pointer, this will almost always lead to a + miscompile. */ + if (!dbg_cnt(dce)) + continue; + + if (dump_file) + fprintf(dump_file, "DCE: Deleting insn %d\n", INSN_UID(insn)); + + /* Before we delete the insn we have to remove the REG_EQUAL notes + for the destination regs in order to avoid dangling notes. */ + remove_reg_equal_equiv_notes_for_defs(insn); + + if (turn_into_use) { - gcc_assert (can_alter_cfg); - delete_unreachable_blocks (); - free_dominance_info (CDI_DOMINATORS); + /* Don't remove frame related noop moves if they cary + REG_CFA_RESTORE note, while we don't need to emit any code, + we need it to emit the CFI restore note. */ + PATTERN(insn) = gen_rtx_USE(GET_MODE(turn_into_use), turn_into_use); + INSN_CODE(insn) = -1; + df_insn_rescan(insn); } -} + else + /* Now delete the insn. */ + must_clean |= delete_insn_and_edges(insn); + } + /* Deleted a pure or const call. */ + if (must_clean) + { + gcc_assert(can_alter_cfg); + delete_unreachable_blocks(); + free_dominance_info(CDI_DOMINATORS); + } +} /* Go through the instructions and mark those whose necessity is not dependent on inter-instruction information. Make sure all other instructions are not marked. */ static void -prescan_insns_for_dce (bool fast) +prescan_insns_for_dce(bool fast) { basic_block bb; rtx_insn *insn, *prev; bitmap arg_stores = NULL; if (dump_file) - fprintf (dump_file, "Finding needed instructions:\n"); + fprintf(dump_file, "Finding needed instructions:\n"); if (!df_in_progress && ACCUMULATE_OUTGOING_ARGS) - arg_stores = BITMAP_ALLOC (NULL); + arg_stores = BITMAP_ALLOC(NULL); - FOR_EACH_BB_FN (bb, cfun) + FOR_EACH_BB_FN(bb, cfun) + { + FOR_BB_INSNS_REVERSE_SAFE(bb, insn, prev) + if (NONDEBUG_INSN_P(insn)) { - FOR_BB_INSNS_REVERSE_SAFE (bb, insn, prev) - if (NONDEBUG_INSN_P (insn)) - { - /* Don't mark argument stores now. They will be marked - if needed when the associated CALL is marked. */ - if (arg_stores && bitmap_bit_p (arg_stores, INSN_UID (insn))) - continue; - if (deletable_insn_p (insn, fast, arg_stores)) - mark_nonreg_stores (insn, fast); - else - mark_insn (insn, fast); - } - /* find_call_stack_args only looks at argument stores in the - same bb. */ - if (arg_stores) - bitmap_clear (arg_stores); + /* Don't mark argument stores now. They will be marked + if needed when the associated CALL is marked. */ + if (arg_stores && bitmap_bit_p(arg_stores, INSN_UID(insn))) + continue; + if (deletable_insn_p(insn, fast, arg_stores)) + mark_nonreg_stores(insn, fast); + else + mark_insn(insn, fast); } + /* find_call_stack_args only looks at argument stores in the + same bb. */ + if (arg_stores) + bitmap_clear(arg_stores); + } if (arg_stores) - BITMAP_FREE (arg_stores); + BITMAP_FREE(arg_stores); if (dump_file) - fprintf (dump_file, "Finished finding needed instructions:\n"); + fprintf(dump_file, "Finished finding needed instructions:\n"); } - /* UD-based DSE routines. */ /* Mark instructions that define artificially-used registers, such as the frame pointer and the stack pointer. */ static void -mark_artificial_uses (void) +mark_artificial_uses(void) { basic_block bb; struct df_link *defs; df_ref use; - FOR_ALL_BB_FN (bb, cfun) - FOR_EACH_ARTIFICIAL_USE (use, bb->index) - for (defs = DF_REF_CHAIN (use); defs; defs = defs->next) - if (!DF_REF_IS_ARTIFICIAL (defs->ref)) - mark_insn (DF_REF_INSN (defs->ref), false); + FOR_ALL_BB_FN(bb, cfun) + FOR_EACH_ARTIFICIAL_USE(use, bb->index) + for (defs = DF_REF_CHAIN(use); defs; defs = defs->next) + if (!DF_REF_IS_ARTIFICIAL(defs->ref)) + mark_insn(DF_REF_INSN(defs->ref), false); } - /* Mark every instruction that defines a register value that INSN uses. */ static void -mark_reg_dependencies (rtx_insn *insn) +mark_reg_dependencies(rtx_insn *insn) { struct df_link *defs; df_ref use; - if (DEBUG_INSN_P (insn)) + if (DEBUG_INSN_P(insn)) return; - FOR_EACH_INSN_USE (use, insn) + FOR_EACH_INSN_USE(use, insn) + { + if (dump_file) { - if (dump_file) - { - fprintf (dump_file, "Processing use of "); - print_simple_rtl (dump_file, DF_REF_REG (use)); - fprintf (dump_file, " in insn %d:\n", INSN_UID (insn)); - } - for (defs = DF_REF_CHAIN (use); defs; defs = defs->next) - if (! DF_REF_IS_ARTIFICIAL (defs->ref)) - mark_insn (DF_REF_INSN (defs->ref), false); + fprintf(dump_file, "Processing use of "); + print_simple_rtl(dump_file, DF_REF_REG(use)); + fprintf(dump_file, " in insn %d:\n", INSN_UID(insn)); } + for (defs = DF_REF_CHAIN(use); defs; defs = defs->next) + if (!DF_REF_IS_ARTIFICIAL(defs->ref)) + mark_insn(DF_REF_INSN(defs->ref), false); + } } - /* Initialize global variables for a new DCE pass. */ static void -init_dce (bool fast) +init_dce(bool fast) { if (!df_in_progress) + { + if (!fast) { - if (!fast) - { - df_set_flags (DF_RD_PRUNE_DEAD_DEFS); - df_chain_add_problem (DF_UD_CHAIN); - } - df_analyze (); + df_set_flags(DF_RD_PRUNE_DEAD_DEFS); + df_chain_add_problem(DF_UD_CHAIN); } + df_analyze(); + } if (dump_file) - df_dump (dump_file); + df_dump(dump_file); if (fast) - { - bitmap_obstack_initialize (&dce_blocks_bitmap_obstack); - bitmap_obstack_initialize (&dce_tmp_bitmap_obstack); - can_alter_cfg = false; - } + { + bitmap_obstack_initialize(&dce_blocks_bitmap_obstack); + bitmap_obstack_initialize(&dce_tmp_bitmap_obstack); + can_alter_cfg = false; + } else can_alter_cfg = true; - marked = sbitmap_alloc (get_max_uid () + 1); - bitmap_clear (marked); + marked = sbitmap_alloc(get_max_uid() + 1); + bitmap_clear(marked); } - /* Free the data allocated by init_dce. */ static void -fini_dce (bool fast) +fini_dce(bool fast) { - sbitmap_free (marked); + sbitmap_free(marked); if (fast) - { - bitmap_obstack_release (&dce_blocks_bitmap_obstack); - bitmap_obstack_release (&dce_tmp_bitmap_obstack); - } + { + bitmap_obstack_release(&dce_blocks_bitmap_obstack); + bitmap_obstack_release(&dce_tmp_bitmap_obstack); + } } - /* UD-chain based DCE. */ static unsigned int -rest_of_handle_ud_dce (void) +rest_of_handle_ud_dce(void) { rtx_insn *insn; - init_dce (false); + init_dce(false); - prescan_insns_for_dce (false); - mark_artificial_uses (); - while (worklist.length () > 0) - { - insn = worklist.pop (); - mark_reg_dependencies (insn); - } - worklist.release (); + prescan_insns_for_dce(false); + mark_artificial_uses(); + while (worklist.length() > 0) + { + insn = worklist.pop(); + mark_reg_dependencies(insn); + } + worklist.release(); if (MAY_HAVE_DEBUG_BIND_INSNS) - reset_unmarked_insns_debug_uses (); + reset_unmarked_insns_debug_uses(); /* Before any insns are deleted, we must remove the chains since they are not bidirectional. */ - df_remove_problem (df_chain); - delete_unmarked_insns (); + df_remove_problem(df_chain); + delete_unmarked_insns(); - fini_dce (false); + fini_dce(false); return 0; } - -namespace { - -const pass_data pass_data_ud_rtl_dce = +namespace { - RTL_PASS, /* type */ - "ud_dce", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - TV_DCE, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_df_finish, /* todo_flags_finish */ -}; -class pass_ud_rtl_dce : public rtl_opt_pass -{ -public: - pass_ud_rtl_dce (gcc::context *ctxt) - : rtl_opt_pass (pass_data_ud_rtl_dce, ctxt) - {} + const pass_data pass_data_ud_rtl_dce = + { + RTL_PASS, /* type */ + "ud_dce", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_DCE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_df_finish, /* todo_flags_finish */ + }; + + class pass_ud_rtl_dce : public rtl_opt_pass + { + public: + pass_ud_rtl_dce(gcc::context *ctxt) + : rtl_opt_pass(pass_data_ud_rtl_dce, ctxt) + { + } - /* opt_pass methods: */ - bool gate (function *) final override + /* opt_pass methods: */ + bool gate(function *) final override { - return optimize > 1 && flag_dce && dbg_cnt (dce_ud); + return optimize > 1 && flag_dce && dbg_cnt(dce_ud); } - unsigned int execute (function *) final override + unsigned int execute(function *) final override { - return rest_of_handle_ud_dce (); + return rest_of_handle_ud_dce(); } -}; // class pass_ud_rtl_dce + }; // class pass_ud_rtl_dce } // anon namespace rtl_opt_pass * -make_pass_ud_rtl_dce (gcc::context *ctxt) +make_pass_ud_rtl_dce(gcc::context *ctxt) { - return new pass_ud_rtl_dce (ctxt); + return new pass_ud_rtl_dce(ctxt); } - /* ------------------------------------------------------------------------- Fast DCE functions ------------------------------------------------------------------------- */ @@ -886,97 +841,91 @@ make_pass_ud_rtl_dce (gcc::context *ctxt) in debug insns using GLOBAL_DEBUG. */ static bool -word_dce_process_block (basic_block bb, bool redo_out, - struct dead_debug_global *global_debug) +word_dce_process_block(basic_block bb, bool redo_out, + struct dead_debug_global *global_debug) { - bitmap local_live = BITMAP_ALLOC (&dce_tmp_bitmap_obstack); + bitmap local_live = BITMAP_ALLOC(&dce_tmp_bitmap_obstack); rtx_insn *insn; bool block_changed; struct dead_debug_local debug; if (redo_out) - { - /* Need to redo the live_out set of this block if when one of - the succs of this block has had a change in it live in - set. */ - edge e; - edge_iterator ei; - df_confluence_function_n con_fun_n = df_word_lr->problem->con_fun_n; - bitmap_clear (DF_WORD_LR_OUT (bb)); - FOR_EACH_EDGE (e, ei, bb->succs) - (*con_fun_n) (e); - } + { + /* Need to redo the live_out set of this block if when one of + the succs of this block has had a change in it live in + set. */ + edge e; + edge_iterator ei; + df_confluence_function_n con_fun_n = df_word_lr->problem->con_fun_n; + bitmap_clear(DF_WORD_LR_OUT(bb)); + FOR_EACH_EDGE(e, ei, bb->succs) + (*con_fun_n)(e); + } if (dump_file) + { + fprintf(dump_file, "processing block %d live out = ", bb->index); + df_print_word_regset(dump_file, DF_WORD_LR_OUT(bb)); + } + + bitmap_copy(local_live, DF_WORD_LR_OUT(bb)); + dead_debug_local_init(&debug, NULL, global_debug); + + FOR_BB_INSNS_REVERSE(bb, insn) + if (DEBUG_INSN_P(insn)) + { + df_ref use; + FOR_EACH_INSN_USE(use, insn) + if (DF_REF_REGNO(use) >= FIRST_PSEUDO_REGISTER && known_eq(GET_MODE_SIZE(GET_MODE(DF_REF_REAL_REG(use))), 2 * UNITS_PER_WORD) && !bitmap_bit_p(local_live, 2 * DF_REF_REGNO(use)) && !bitmap_bit_p(local_live, 2 * DF_REF_REGNO(use) + 1)) + dead_debug_add(&debug, use, DF_REF_REGNO(use)); + } + 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); + if (any_changed) + mark_insn(insn, true); + + /* On the other hand, we do not allow the dead uses to set + anything in local_live. */ + if (marked_insn_p(insn)) + df_word_lr_simulate_uses(insn, local_live); + + /* Insert debug temps for dead REGs used in subsequent debug + insns. We may have to emit a debug temp even if the insn + was marked, in case the debug use was after the point of + death. */ + if (debug.used && !bitmap_empty_p(debug.used)) { - fprintf (dump_file, "processing block %d live out = ", bb->index); - df_print_word_regset (dump_file, DF_WORD_LR_OUT (bb)); - } + df_ref def; - bitmap_copy (local_live, DF_WORD_LR_OUT (bb)); - dead_debug_local_init (&debug, NULL, global_debug); + FOR_EACH_INSN_DEF(def, insn) + dead_debug_insert_temp(&debug, DF_REF_REGNO(def), insn, + marked_insn_p(insn) && !control_flow_insn_p(insn) + ? DEBUG_TEMP_AFTER_WITH_REG_FORCE + : DEBUG_TEMP_BEFORE_WITH_VALUE); + } - FOR_BB_INSNS_REVERSE (bb, insn) - if (DEBUG_INSN_P (insn)) - { - df_ref use; - FOR_EACH_INSN_USE (use, insn) - if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER - && known_eq (GET_MODE_SIZE (GET_MODE (DF_REF_REAL_REG (use))), - 2 * UNITS_PER_WORD) - && !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (use)) - && !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (use) + 1)) - dead_debug_add (&debug, use, DF_REF_REGNO (use)); - } - 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); - if (any_changed) - mark_insn (insn, true); - - /* On the other hand, we do not allow the dead uses to set - anything in local_live. */ - if (marked_insn_p (insn)) - df_word_lr_simulate_uses (insn, local_live); - - /* Insert debug temps for dead REGs used in subsequent debug - insns. We may have to emit a debug temp even if the insn - was marked, in case the debug use was after the point of - death. */ - if (debug.used && !bitmap_empty_p (debug.used)) - { - df_ref def; - - FOR_EACH_INSN_DEF (def, insn) - dead_debug_insert_temp (&debug, DF_REF_REGNO (def), insn, - marked_insn_p (insn) - && !control_flow_insn_p (insn) - ? DEBUG_TEMP_AFTER_WITH_REG_FORCE - : DEBUG_TEMP_BEFORE_WITH_VALUE); - } - - if (dump_file) - { - fprintf (dump_file, "finished processing insn %d live out = ", - INSN_UID (insn)); - df_print_word_regset (dump_file, local_live); - } - } + if (dump_file) + { + fprintf(dump_file, "finished processing insn %d live out = ", + INSN_UID(insn)); + df_print_word_regset(dump_file, local_live); + } + } - block_changed = !bitmap_equal_p (local_live, DF_WORD_LR_IN (bb)); + block_changed = !bitmap_equal_p(local_live, DF_WORD_LR_IN(bb)); if (block_changed) - bitmap_copy (DF_WORD_LR_IN (bb), local_live); + bitmap_copy(DF_WORD_LR_IN(bb), local_live); - dead_debug_local_finish (&debug, NULL); - BITMAP_FREE (local_live); + dead_debug_local_finish(&debug, NULL); + BITMAP_FREE(local_live); return block_changed; } - /* Process basic block BB. Return true if the live_in set has changed. REDO_OUT is true if the info at the bottom of the block needs to be recalculated before starting. AU is the proper set of @@ -984,111 +933,108 @@ word_dce_process_block (basic_block bb, bool redo_out, in debug insns using GLOBAL_DEBUG. */ static bool -dce_process_block (basic_block bb, bool redo_out, bitmap au, - struct dead_debug_global *global_debug) +dce_process_block(basic_block bb, bool redo_out, bitmap au, + struct dead_debug_global *global_debug) { - bitmap local_live = BITMAP_ALLOC (&dce_tmp_bitmap_obstack); + bitmap local_live = BITMAP_ALLOC(&dce_tmp_bitmap_obstack); rtx_insn *insn; bool block_changed; df_ref def; struct dead_debug_local debug; if (redo_out) - { - /* Need to redo the live_out set of this block if when one of - the succs of this block has had a change in it live in - set. */ - edge e; - edge_iterator ei; - df_confluence_function_n con_fun_n = df_lr->problem->con_fun_n; - bitmap_clear (DF_LR_OUT (bb)); - FOR_EACH_EDGE (e, ei, bb->succs) - (*con_fun_n) (e); - } + { + /* Need to redo the live_out set of this block if when one of + the succs of this block has had a change in it live in + set. */ + edge e; + edge_iterator ei; + df_confluence_function_n con_fun_n = df_lr->problem->con_fun_n; + bitmap_clear(DF_LR_OUT(bb)); + FOR_EACH_EDGE(e, ei, bb->succs) + (*con_fun_n)(e); + } if (dump_file) + { + fprintf(dump_file, "processing block %d lr out = ", bb->index); + df_print_regset(dump_file, DF_LR_OUT(bb)); + } + + bitmap_copy(local_live, DF_LR_OUT(bb)); + + df_simulate_initialize_backwards(bb, local_live); + dead_debug_local_init(&debug, NULL, global_debug); + + FOR_BB_INSNS_REVERSE(bb, insn) + if (DEBUG_INSN_P(insn)) + { + df_ref use; + FOR_EACH_INSN_USE(use, insn) + if (!bitmap_bit_p(local_live, DF_REF_REGNO(use)) && !bitmap_bit_p(au, DF_REF_REGNO(use))) + dead_debug_add(&debug, use, DF_REF_REGNO(use)); + } + 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_EACH_INSN_DEF(def, insn) + if (bitmap_bit_p(local_live, DF_REF_REGNO(def)) || bitmap_bit_p(au, DF_REF_REGNO(def))) { - fprintf (dump_file, "processing block %d lr out = ", bb->index); - df_print_regset (dump_file, DF_LR_OUT (bb)); + needed = true; + mark_insn(insn, true); + break; } - bitmap_copy (local_live, DF_LR_OUT (bb)); - - df_simulate_initialize_backwards (bb, local_live); - dead_debug_local_init (&debug, NULL, global_debug); - - FOR_BB_INSNS_REVERSE (bb, insn) - if (DEBUG_INSN_P (insn)) - { - df_ref use; - FOR_EACH_INSN_USE (use, insn) - if (!bitmap_bit_p (local_live, DF_REF_REGNO (use)) - && !bitmap_bit_p (au, DF_REF_REGNO (use))) - dead_debug_add (&debug, use, DF_REF_REGNO (use)); - } - 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_EACH_INSN_DEF (def, insn) - if (bitmap_bit_p (local_live, DF_REF_REGNO (def)) - || bitmap_bit_p (au, DF_REF_REGNO (def))) - { - 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. */ - df_simulate_defs (insn, local_live); - - /* On the other hand, we do not allow the dead uses to set - anything in local_live. */ - if (needed) - df_simulate_uses (insn, local_live); - - /* Insert debug temps for dead REGs used in subsequent debug - insns. We may have to emit a debug temp even if the insn - was marked, in case the debug use was after the point of - death. */ - if (debug.used && !bitmap_empty_p (debug.used)) - FOR_EACH_INSN_DEF (def, insn) - dead_debug_insert_temp (&debug, DF_REF_REGNO (def), insn, - needed && !control_flow_insn_p (insn) - ? DEBUG_TEMP_AFTER_WITH_REG_FORCE - : DEBUG_TEMP_BEFORE_WITH_VALUE); - } - - dead_debug_local_finish (&debug, NULL); - df_simulate_finalize_backwards (bb, local_live); - - block_changed = !bitmap_equal_p (local_live, DF_LR_IN (bb)); + /* No matter if the instruction is needed or not, we remove + any regno in the defs from the live set. */ + df_simulate_defs(insn, local_live); + + /* On the other hand, we do not allow the dead uses to set + anything in local_live. */ + if (needed) + df_simulate_uses(insn, local_live); + + /* Insert debug temps for dead REGs used in subsequent debug + insns. We may have to emit a debug temp even if the insn + was marked, in case the debug use was after the point of + death. */ + if (debug.used && !bitmap_empty_p(debug.used)) + FOR_EACH_INSN_DEF(def, insn) + dead_debug_insert_temp(&debug, DF_REF_REGNO(def), insn, + needed && !control_flow_insn_p(insn) + ? DEBUG_TEMP_AFTER_WITH_REG_FORCE + : DEBUG_TEMP_BEFORE_WITH_VALUE); + } + + dead_debug_local_finish(&debug, NULL); + df_simulate_finalize_backwards(bb, local_live); + + block_changed = !bitmap_equal_p(local_live, DF_LR_IN(bb)); if (block_changed) - bitmap_copy (DF_LR_IN (bb), local_live); + bitmap_copy(DF_LR_IN(bb), local_live); - BITMAP_FREE (local_live); + BITMAP_FREE(local_live); return block_changed; } - /* Perform fast DCE once initialization is done. If WORD_LEVEL is true, use the word level dce, otherwise do it at the pseudo level. */ static void -fast_dce (bool word_level) +fast_dce(bool word_level) { - int *postorder = df_get_postorder (DF_BACKWARD); - int n_blocks = df_get_n_blocks (DF_BACKWARD); + int *postorder = df_get_postorder(DF_BACKWARD); + int n_blocks = df_get_n_blocks(DF_BACKWARD); /* The set of blocks that have been seen on this iteration. */ - bitmap processed = BITMAP_ALLOC (&dce_blocks_bitmap_obstack); + bitmap processed = BITMAP_ALLOC(&dce_blocks_bitmap_obstack); /* The set of blocks that need to have the out vectors reset because the in of one of their successors has changed. */ - bitmap redo_out = BITMAP_ALLOC (&dce_blocks_bitmap_obstack); - bitmap all_blocks = BITMAP_ALLOC (&dce_blocks_bitmap_obstack); + bitmap redo_out = BITMAP_ALLOC(&dce_blocks_bitmap_obstack); + bitmap all_blocks = BITMAP_ALLOC(&dce_blocks_bitmap_obstack); bool global_changed = true; /* These regs are considered always live so if they end up dying @@ -1101,128 +1047,122 @@ fast_dce (bool word_level) int i; struct dead_debug_global global_debug; - prescan_insns_for_dce (true); + prescan_insns_for_dce(true); for (i = 0; i < n_blocks; i++) - bitmap_set_bit (all_blocks, postorder[i]); + bitmap_set_bit(all_blocks, postorder[i]); - dead_debug_global_init (&global_debug, NULL); + dead_debug_global_init(&global_debug, NULL); while (global_changed) + { + global_changed = false; + + for (i = 0; i < n_blocks; i++) + { + int index = postorder[i]; + basic_block bb = BASIC_BLOCK_FOR_FN(cfun, index); + bool local_changed; + + if (index < NUM_FIXED_BLOCKS) + { + bitmap_set_bit(processed, index); + continue; + } + + if (word_level) + local_changed = word_dce_process_block(bb, bitmap_bit_p(redo_out, index), + &global_debug); + else + local_changed = dce_process_block(bb, bitmap_bit_p(redo_out, index), + bb_has_eh_pred(bb) ? au_eh : au, + &global_debug); + bitmap_set_bit(processed, index); + + if (local_changed) + { + edge e; + edge_iterator ei; + FOR_EACH_EDGE(e, ei, bb->preds) + if (bitmap_bit_p(processed, e->src->index)) + /* Be tricky about when we need to iterate the + analysis. We only have redo the analysis if the + bitmaps change at the top of a block that is the + entry to a loop. */ + global_changed = true; + else + bitmap_set_bit(redo_out, e->src->index); + } + } + + if (global_changed) { - global_changed = false; - - for (i = 0; i < n_blocks; i++) - { - int index = postorder[i]; - basic_block bb = BASIC_BLOCK_FOR_FN (cfun, index); - bool local_changed; - - if (index < NUM_FIXED_BLOCKS) - { - bitmap_set_bit (processed, index); - continue; - } - - if (word_level) - local_changed - = word_dce_process_block (bb, bitmap_bit_p (redo_out, index), - &global_debug); - else - local_changed - = dce_process_block (bb, bitmap_bit_p (redo_out, index), - bb_has_eh_pred (bb) ? au_eh : au, - &global_debug); - bitmap_set_bit (processed, index); - - if (local_changed) - { - edge e; - edge_iterator ei; - FOR_EACH_EDGE (e, ei, bb->preds) - if (bitmap_bit_p (processed, e->src->index)) - /* Be tricky about when we need to iterate the - analysis. We only have redo the analysis if the - bitmaps change at the top of a block that is the - entry to a loop. */ - global_changed = true; - else - bitmap_set_bit (redo_out, e->src->index); - } - } - - if (global_changed) - { - /* Turn off the RUN_DCE flag to prevent recursive calls to - dce. */ - int old_flag = df_clear_flags (DF_LR_RUN_DCE); - - /* So something was deleted that requires a redo. Do it on - the cheap. */ - delete_unmarked_insns (); - bitmap_clear (marked); - bitmap_clear (processed); - bitmap_clear (redo_out); - - /* We do not need to rescan any instructions. We only need - to redo the dataflow equations for the blocks that had a - change at the top of the block. Then we need to redo the - iteration. */ - if (word_level) - df_analyze_problem (df_word_lr, all_blocks, postorder, n_blocks); - else - df_analyze_problem (df_lr, all_blocks, postorder, n_blocks); - - if (old_flag & DF_LR_RUN_DCE) - df_set_flags (DF_LR_RUN_DCE); - - prescan_insns_for_dce (true); - } + /* Turn off the RUN_DCE flag to prevent recursive calls to + dce. */ + int old_flag = df_clear_flags(DF_LR_RUN_DCE); + + /* So something was deleted that requires a redo. Do it on + the cheap. */ + delete_unmarked_insns(); + bitmap_clear(marked); + bitmap_clear(processed); + bitmap_clear(redo_out); + + /* We do not need to rescan any instructions. We only need + to redo the dataflow equations for the blocks that had a + change at the top of the block. Then we need to redo the + iteration. */ + if (word_level) + df_analyze_problem(df_word_lr, all_blocks, postorder, n_blocks); + else + df_analyze_problem(df_lr, all_blocks, postorder, n_blocks); + + if (old_flag & DF_LR_RUN_DCE) + df_set_flags(DF_LR_RUN_DCE); + + prescan_insns_for_dce(true); } + } - dead_debug_global_finish (&global_debug, NULL); + dead_debug_global_finish(&global_debug, NULL); - delete_unmarked_insns (); + delete_unmarked_insns(); - BITMAP_FREE (processed); - BITMAP_FREE (redo_out); - BITMAP_FREE (all_blocks); + BITMAP_FREE(processed); + BITMAP_FREE(redo_out); + BITMAP_FREE(all_blocks); } - /* Fast register level DCE. */ static unsigned int -rest_of_handle_fast_dce (void) +rest_of_handle_fast_dce(void) { - init_dce (true); - fast_dce (false); - fini_dce (true); + init_dce(true); + fast_dce(false); + fini_dce(true); return 0; } - /* Fast byte level DCE. */ -void -run_word_dce (void) +void run_word_dce(void) { int old_flags; if (!flag_dce) return; - timevar_push (TV_DCE); - old_flags = df_clear_flags (DF_DEFER_INSN_RESCAN + DF_NO_INSN_RESCAN); - df_word_lr_add_problem (); - init_dce (true); - fast_dce (true); - fini_dce (true); - df_set_flags (old_flags); - timevar_pop (TV_DCE); + timevar_push(TV_DCE); + old_flags = df_clear_flags(DF_DEFER_INSN_RESCAN + DF_NO_INSN_RESCAN); + df_word_lr_add_problem(); + init_dce(true); + fast_dce(true); + fini_dce(true); + df_set_flags(old_flags); + timevar_pop(TV_DCE); } - /* This is an internal call that is used by the df live register problem to run fast dce as a side effect of creating the live information. The stack is organized so that the lr problem is run, @@ -1232,196 +1172,212 @@ run_word_dce (void) This can be called by elsewhere but it will not update the bit vectors for any other problems than LR. */ -void -run_fast_df_dce (void) +void run_fast_df_dce(void) { if (flag_dce) - { - /* If dce is able to delete something, it has to happen - immediately. Otherwise there will be problems handling the - eq_notes. */ - int old_flags = - df_clear_flags (DF_DEFER_INSN_RESCAN + DF_NO_INSN_RESCAN); - - df_in_progress = true; - rest_of_handle_fast_dce (); - df_in_progress = false; - - df_set_flags (old_flags); - } + { + /* If dce is able to delete something, it has to happen + immediately. Otherwise there will be problems handling the + eq_notes. */ + int old_flags = + df_clear_flags(DF_DEFER_INSN_RESCAN + DF_NO_INSN_RESCAN); + + df_in_progress = true; + rest_of_handle_fast_dce(); + df_in_progress = false; + + df_set_flags(old_flags); + } } - /* Run a fast DCE pass. */ -void -run_fast_dce (void) +void run_fast_dce(void) { if (flag_dce) - rest_of_handle_fast_dce (); + rest_of_handle_fast_dce(); } - -namespace { - -const pass_data pass_data_fast_rtl_dce = +namespace { - RTL_PASS, /* type */ - "rtl_dce", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - TV_DCE, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_df_finish, /* todo_flags_finish */ -}; -class pass_fast_rtl_dce : public rtl_opt_pass -{ -public: - pass_fast_rtl_dce (gcc::context *ctxt) - : rtl_opt_pass (pass_data_fast_rtl_dce, ctxt) - {} + const pass_data pass_data_fast_rtl_dce = + { + RTL_PASS, /* type */ + "rtl_dce", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_DCE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_df_finish, /* todo_flags_finish */ + }; + + class pass_fast_rtl_dce : public rtl_opt_pass + { + public: + pass_fast_rtl_dce(gcc::context *ctxt) + : rtl_opt_pass(pass_data_fast_rtl_dce, ctxt) + { + } - /* opt_pass methods: */ - bool gate (function *) final override + /* opt_pass methods: */ + bool gate(function *) final override { - return optimize > 0 && flag_dce && dbg_cnt (dce_fast); + return optimize > 0 && flag_dce && dbg_cnt(dce_fast); } - unsigned int execute (function *) final override + unsigned int execute(function *) final override { - return rest_of_handle_fast_dce (); + return rest_of_handle_fast_dce(); } -}; // class pass_fast_rtl_dce + }; // class pass_fast_rtl_dce } // namespace - -bool is_inherently_live(insn_info *insn) { - -} - -static void rti_ssa_dce_() { - +bool is_inherently_live(insn_info *insn) +{ } static void -rtl_ssa_dce_init () +rtl_ssa_dce_init() { - calculate_dominance_info (CDI_DOMINATORS); - crtl->ssa = new rtl_ssa::function_info (cfun); + calculate_dominance_info(CDI_DOMINATORS); + crtl->ssa = new rtl_ssa::function_info(cfun); } static void -rtl_ssa_dce_done () +rtl_ssa_dce_done() { - free_dominance_info (CDI_DOMINATORS); - if (crtl->ssa->perform_pending_updates ()) - cleanup_cfg (0); + free_dominance_info(CDI_DOMINATORS); + if (crtl->ssa->perform_pending_updates()) + cleanup_cfg(0); - delete crtl->ssa; - crtl->ssa = nullptr; + delete crtl->ssa; + crtl->ssa = nullptr; - if (dump_file) - fprintf (dump_file, "\nFinished running rtl_ssa_dce\n\n"); + if (dump_file) + fprintf(dump_file, "\nFinished running rtl_ssa_dce\n\n"); } -static unsigned int -rtl_ssa_dce () +static void +rtl_ssa_dce_mark(sbitmap marked) { - rtl_ssa_dce_init (); - - insn_info *next; - sbitmap marked; - auto_vec<insn_info *> worklist; - for (insn_info *insn = crtl->ssa->first_insn (); insn; insn = next) - { - next = insn->next_any_insn (); - auto *rtl = insn->rtl(); - /* - I would like to mark visited instruction with something like plf (Pass local flags) as in gimple - - This file contains some useful functions: e.g. marked_insn_p, mark_insn - mark_insn does much more than I want now... - It does quite a useful job. If rtl_insn is a call and it is obsolete, it will find call arguments. - */ - // insn.defs() // UD chain - this is what I want - reach the ancestors\ + insn_info *next; + auto_vec<insn_info *> worklist; + for (insn_info *insn = crtl->ssa->first_insn(); insn; insn = next) + { + next = insn->next_any_insn(); + /* + I would like to mark visited instruction with something like plf (Pass local flags) as in gimple + + This file contains some useful functions: e.g. marked_insn_p, mark_insn + mark_insn does much more than I want now... + It does quite a useful job. If rtl_insn is a call and it is obsolete, it will find call arguments. + */ + // insn.defs() // UD chain - this is what I want - reach the ancestors\ // insn.uses() // DU chain - if (is_inherently_live(insn)) { - if (dump_file) - fprintf (dump_file, " Adding insn %d to worklist\n", INSN_UID (insn)); - worklist.safe_push (insn); - bitmap_set_bit(marked, INSN_UID (insn)); - } - - //if (insn->can_be_optimized () || insn->is_debug_insn ()) - // if (fwprop_insn (insn, fwprop_addr_p)) - // worklist.safe_push (insn); + if (is_inherently_live(insn)) + { + if (dump_file) + fprintf(dump_file, " Adding insn %d to worklist\n", INSN_UID(insn->rtl())); + worklist.safe_push(insn); + bitmap_set_bit(marked, INSN_UID(insn->rtl())); } - while (!worklist.is_empty()) + // if (insn->can_be_optimized () || insn->is_debug_insn ()) + // if (fwprop_insn (insn, fwprop_addr_p)) + // worklist.safe_push (insn); + } + + while (!worklist.is_empty()) + { + insn_info *insn = worklist.pop(); + def_array defs = insn->defs(); // array - because of phi? + for (size_t i = 0; i < defs.size(); i++) { - insn_info *insn = worklist.pop(); - def_array defs = insn->defs(); // array - because of phi? - for (size_t i = 0; i < defs.size(); i++) - { - insn_info* parent_insn = defs[i]->insn(); + insn_info *parent_insn = defs[i]->insn(); - if (!bitmap_bit_p(INSN_UID (parent_insn))) { - if (dump_file) - fprintf (dump_file, " Adding insn %d to worklist\n", INSN_UID (parent_insn)); - worklist.safe_push(parent_insn); - bitmap_set_bit(marked, INSN_UID (parent_insn)); - } + if (!bitmap_bit_p(marked, INSN_UID(parent_insn->rtl()))) + { + if (dump_file) + fprintf(dump_file, " Adding insn %d to worklist\n", INSN_UID(parent_insn->rtl())); + worklist.safe_push(parent_insn); + bitmap_set_bit(marked, INSN_UID(parent_insn->rtl())); } } - - rtl_ssa_dce_done (); - return 0; + } } -rtl_opt_pass * -make_pass_fast_rtl_dce (gcc::context *ctxt) +static void +rtl_ssa_dce_sweep(sbitmap marked) { - return new pass_fast_rtl_dce (ctxt); + insn_info *next; + for (insn_info *insn = crtl->ssa->first_insn(); insn; insn = next) + { + if (!bitmap_bit_p(marked, INSN_UID(insn->rtl()))) { + insn->rtl()->set_deleted(); + // delete + } + } } -namespace { - -const pass_data pass_data_rtl_ssa_dce = { - RTL_PASS, /* type */ - "rtl_ssa_dce", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - TV_DCE, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_df_finish, /* todo_flags_finish */ -}; +static unsigned int +rtl_ssa_dce() +{ + rtl_ssa_dce_init(); + + sbitmap marked; + rtl_ssa_dce_mark(marked); + rtl_ssa_dce_sweep(marked); + + rtl_ssa_dce_done(); + return 0; +} + +rtl_opt_pass * +make_pass_fast_rtl_dce(gcc::context *ctxt) +{ + return new pass_fast_rtl_dce(ctxt); +} -class pass_rtl_ssa_dce : public rtl_opt_pass +namespace { -public: - pass_rtl_ssa_dce (gcc::context *ctxt) - : rtl_opt_pass (pass_data_rtl_ssa_dce, ctxt) - {} - /* opt_pass methods: */ - bool gate (function *) final override { return flag_dce; } + const pass_data pass_data_rtl_ssa_dce = { + RTL_PASS, /* type */ + "rtl_ssa_dce", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_DCE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_df_finish, /* todo_flags_finish */ + }; + + class pass_rtl_ssa_dce : public rtl_opt_pass + { + public: + pass_rtl_ssa_dce(gcc::context *ctxt) + : rtl_opt_pass(pass_data_rtl_ssa_dce, ctxt) + { + } + + /* opt_pass methods: */ + bool gate(function *) final override { return flag_dce; } - unsigned int execute (function *) final override { return rtl_ssa_dce (); } + unsigned int execute(function *) final override { return rtl_ssa_dce(); } -}; // class pass_fast_rtl_dce + }; // class pass_fast_rtl_dce } // namespace rtl_opt_pass * -make_pass_rtl_ssa_dce (gcc::context *ctxt) +make_pass_rtl_ssa_dce(gcc::context *ctxt) { - return new pass_rtl_ssa_dce (ctxt); + return new pass_rtl_ssa_dce(ctxt); }