Mercurial > hg > CbC > CbC_gcc
diff gcc/dce.c @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
line wrap: on
line diff
--- a/gcc/dce.c Thu Oct 25 07:37:49 2018 +0900 +++ b/gcc/dce.c Thu Feb 13 11:34:05 2020 +0900 @@ -1,5 +1,5 @@ /* RTL dead code elimination. - Copyright (C) 2005-2018 Free Software Foundation, Inc. + Copyright (C) 2005-2020 Free Software Foundation, Inc. This file is part of GCC. @@ -35,6 +35,7 @@ #include "valtrack.h" #include "tree-pass.h" #include "dbgcnt.h" +#include "rtl-iter.h" /* ------------------------------------------------------------------------- @@ -86,6 +87,32 @@ } } +/* Don't delete calls that may throw if we cannot do so. */ + +static bool +can_delete_call (rtx_insn *insn) +{ + if (cfun->can_delete_dead_exceptions && can_alter_cfg) + return true; + 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; + } + return true; +} /* Return true if INSN is a normal instruction that can be deleted by the DCE pass. */ @@ -108,7 +135,9 @@ /* 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_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); @@ -145,7 +174,6 @@ return false; case CLOBBER: - case CLOBBER_HIGH: if (fast) { /* A CLOBBER of a dead pseudo register serves no purpose. @@ -201,7 +229,8 @@ && !df_in_progress && !SIBLING_CALL_P (insn) && (RTL_CONST_OR_PURE_CALL_P (insn) - && !RTL_LOOPING_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); } } @@ -214,10 +243,7 @@ mark_nonreg_stores_1 (rtx dest, const_rtx pattern, void *data) { if (GET_CODE (pattern) != CLOBBER && !REG_P (dest)) - { - gcc_checking_assert (GET_CODE (pattern) != CLOBBER_HIGH); - mark_insn ((rtx_insn *) data, true); - } + mark_insn ((rtx_insn *) data, true); } @@ -228,22 +254,19 @@ mark_nonreg_stores_2 (rtx dest, const_rtx pattern, void *data) { if (GET_CODE (pattern) != CLOBBER && !REG_P (dest)) - { - gcc_checking_assert (GET_CODE (pattern) != CLOBBER_HIGH); - mark_insn ((rtx_insn *) data, false); - } + mark_insn ((rtx_insn *) data, false); } -/* Mark INSN if BODY stores to a non-register destination. */ +/* Mark INSN if it stores to a non-register destination. */ static void -mark_nonreg_stores (rtx body, rtx_insn *insn, bool fast) +mark_nonreg_stores (rtx_insn *insn, bool fast) { if (fast) - note_stores (body, mark_nonreg_stores_1, insn); + note_stores (insn, mark_nonreg_stores_1, insn); else - note_stores (body, mark_nonreg_stores_2, insn); + note_stores (insn, mark_nonreg_stores_2, insn); } @@ -267,6 +290,100 @@ return true; } +/* If MEM has sp address, return 0, if it has sp + const address, + return that const, if it has reg address where reg is set to sp + const + and FAST is false, return const, otherwise return + INTTYPE_MINUMUM (HOST_WIDE_INT). */ + +static HOST_WIDE_INT +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); + } + if (addr == stack_pointer_rtx) + return off; + + 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))) + break; + + if (use == NULL) + 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)) + break; + + if (defs == NULL) + return INTTYPE_MINIMUM (HOST_WIDE_INT); + + rtx set = single_set (DF_REF_INSN (defs->ref)); + if (!set) + 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)); + return off; +} + +/* Data for check_argument_load called via note_uses. */ +struct check_argument_load_data { + bitmap sp_bytes; + HOST_WIDE_INT min_sp_off, max_sp_off; + rtx_call_insn *call_insn; + bool fast; + bool load_found; +}; + +/* Helper function for find_call_stack_args. Check if there are + any loads from the argument slots in between the const/pure call + and store to the argument slot, set LOAD_FOUND if any is found. */ + +static void +check_argument_load (rtx *loc, void *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) + { + 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; + } + } + } +} /* Try to find all stack stores of CALL_INSN arguments if ACCUMULATE_OUTGOING_ARGS. If all stack stores have been found @@ -304,58 +421,13 @@ if (GET_CODE (XEXP (p, 0)) == USE && MEM_P (XEXP (XEXP (p, 0), 0))) { - rtx mem = XEXP (XEXP (p, 0), 0), addr; - HOST_WIDE_INT off = 0, size; + 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; - 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) - { - if (!REG_P (addr)) - return false; - /* If not fast, use chains to see if addr wasn't set to - sp + offset. */ - if (!fast) - { - df_ref use; - struct df_link *defs; - rtx set; - - FOR_EACH_INSN_USE (use, call_insn) - if (rtx_equal_p (addr, DF_REF_REG (use))) - break; - - if (use == NULL) - return false; - - for (defs = DF_REF_CHAIN (use); defs; defs = defs->next) - if (! DF_REF_IS_ARTIFICIAL (defs->ref)) - break; - - if (defs == NULL) - return false; - - set = single_set (DF_REF_INSN (defs->ref)); - if (!set) - return false; - - if (GET_CODE (SET_SRC (set)) != PLUS - || XEXP (SET_SRC (set), 0) != stack_pointer_rtx - || !CONST_INT_P (XEXP (SET_SRC (set), 1))) - return false; - - off += INTVAL (XEXP (SET_SRC (set), 1)); - } - else - 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); } @@ -371,51 +443,24 @@ if (GET_CODE (XEXP (p, 0)) == USE && MEM_P (XEXP (XEXP (p, 0), 0))) { - rtx mem = XEXP (XEXP (p, 0), 0), addr; - HOST_WIDE_INT off = 0, byte, size; + rtx mem = XEXP (XEXP (p, 0), 0); /* Checked in the previous iteration. */ - size = MEM_SIZE (mem).to_constant (); - 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) - { - df_ref use; - struct df_link *defs; - rtx set; - - FOR_EACH_INSN_USE (use, call_insn) - if (rtx_equal_p (addr, DF_REF_REG (use))) - break; - - for (defs = DF_REF_CHAIN (use); defs; defs = defs->next) - if (! DF_REF_IS_ARTIFICIAL (defs->ref)) - break; - - set = single_set (DF_REF_INSN (defs->ref)); - off += INTVAL (XEXP (SET_SRC (set), 1)); - } - for (byte = off; byte < off + size; byte++) - { - if (!bitmap_set_bit (sp_bytes, byte - min_sp_off)) - gcc_unreachable (); - } + 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 or memory store other than - argument store. */ + 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 }; ret = false; for (insn = PREV_INSN (call_insn); insn; insn = prev_insn) { - rtx set, mem, addr; - HOST_WIDE_INT off; - if (insn == BB_HEAD (BLOCK_FOR_INSN (call_insn))) prev_insn = NULL; else @@ -427,61 +472,21 @@ if (!NONDEBUG_INSN_P (insn)) continue; - set = single_set (insn); + 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; + if (!MEM_P (SET_DEST (set))) continue; - mem = SET_DEST (set); - addr = XEXP (mem, 0); - off = 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) - { - if (!REG_P (addr)) - break; - if (!fast) - { - df_ref use; - struct df_link *defs; - rtx set; - - FOR_EACH_INSN_USE (use, insn) - if (rtx_equal_p (addr, DF_REF_REG (use))) - break; - - if (use == NULL) - break; - - for (defs = DF_REF_CHAIN (use); defs; defs = defs->next) - if (! DF_REF_IS_ARTIFICIAL (defs->ref)) - break; - - if (defs == NULL) - break; - - set = single_set (DF_REF_INSN (defs->ref)); - if (!set) - break; - - if (GET_CODE (SET_SRC (set)) != PLUS - || XEXP (SET_SRC (set), 0) != stack_pointer_rtx - || !CONST_INT_P (XEXP (SET_SRC (set), 1))) - break; - - off += INTVAL (XEXP (SET_SRC (set), 1)); - } - else - 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) @@ -579,7 +584,12 @@ rtx turn_into_use = NULL_RTX; /* Always delete no-op moves. */ - if (noop_move_p (insn)) + 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 @@ -622,12 +632,6 @@ for the destination regs in order to avoid dangling notes. */ remove_reg_equal_equiv_notes_for_defs (insn); - /* If a pure or const call is deleted, this may make the cfg - have unreachable blocks. We rememeber this and call - delete_unreachable_blocks at the end. */ - if (CALL_P (insn)) - must_clean = true; - if (turn_into_use) { /* Don't remove frame related noop moves if they cary @@ -640,12 +644,16 @@ } else /* Now delete the insn. */ - delete_insn_and_edges (insn); + must_clean |= delete_insn_and_edges (insn); } /* Deleted a pure or const call. */ if (must_clean) - delete_unreachable_blocks (); + { + gcc_assert (can_alter_cfg); + delete_unreachable_blocks (); + free_dominance_info (CDI_DOMINATORS); + } } @@ -676,7 +684,7 @@ if (arg_stores && bitmap_bit_p (arg_stores, INSN_UID (insn))) continue; if (deletable_insn_p (insn, fast, arg_stores)) - mark_nonreg_stores (PATTERN (insn), insn, fast); + mark_nonreg_stores (insn, fast); else mark_insn (insn, fast); }