138fd1498Szrj /* RTL dead code elimination.
238fd1498Szrj Copyright (C) 2005-2018 Free Software Foundation, Inc.
338fd1498Szrj
438fd1498Szrj This file is part of GCC.
538fd1498Szrj
638fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
738fd1498Szrj the terms of the GNU General Public License as published by the Free
838fd1498Szrj Software Foundation; either version 3, or (at your option) any later
938fd1498Szrj version.
1038fd1498Szrj
1138fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1238fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1338fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1438fd1498Szrj for more details.
1538fd1498Szrj
1638fd1498Szrj You should have received a copy of the GNU General Public License
1738fd1498Szrj along with GCC; see the file COPYING3. If not see
1838fd1498Szrj <http://www.gnu.org/licenses/>. */
1938fd1498Szrj
2038fd1498Szrj #include "config.h"
2138fd1498Szrj #include "system.h"
2238fd1498Szrj #include "coretypes.h"
2338fd1498Szrj #include "backend.h"
2438fd1498Szrj #include "rtl.h"
2538fd1498Szrj #include "tree.h"
2638fd1498Szrj #include "predict.h"
2738fd1498Szrj #include "df.h"
2838fd1498Szrj #include "memmodel.h"
2938fd1498Szrj #include "tm_p.h"
3038fd1498Szrj #include "emit-rtl.h" /* FIXME: Can go away once crtl is moved to rtl.h. */
3138fd1498Szrj #include "cfgrtl.h"
3238fd1498Szrj #include "cfgbuild.h"
3338fd1498Szrj #include "cfgcleanup.h"
3438fd1498Szrj #include "dce.h"
3538fd1498Szrj #include "valtrack.h"
3638fd1498Szrj #include "tree-pass.h"
3738fd1498Szrj #include "dbgcnt.h"
3838fd1498Szrj
3938fd1498Szrj
4038fd1498Szrj /* -------------------------------------------------------------------------
4138fd1498Szrj Core mark/delete routines
4238fd1498Szrj ------------------------------------------------------------------------- */
4338fd1498Szrj
4438fd1498Szrj /* True if we are invoked while the df engine is running; in this case,
4538fd1498Szrj we don't want to reenter it. */
4638fd1498Szrj static bool df_in_progress = false;
4738fd1498Szrj
4838fd1498Szrj /* True if we are allowed to alter the CFG in this pass. */
4938fd1498Szrj static bool can_alter_cfg = false;
5038fd1498Szrj
5138fd1498Szrj /* Instructions that have been marked but whose dependencies have not
5238fd1498Szrj yet been processed. */
5338fd1498Szrj static vec<rtx_insn *> worklist;
5438fd1498Szrj
5538fd1498Szrj /* Bitmap of instructions marked as needed indexed by INSN_UID. */
5638fd1498Szrj static sbitmap marked;
5738fd1498Szrj
5838fd1498Szrj /* Bitmap obstacks used for block processing by the fast algorithm. */
5938fd1498Szrj static bitmap_obstack dce_blocks_bitmap_obstack;
6038fd1498Szrj static bitmap_obstack dce_tmp_bitmap_obstack;
6138fd1498Szrj
6238fd1498Szrj static bool find_call_stack_args (rtx_call_insn *, bool, bool, bitmap);
6338fd1498Szrj
6438fd1498Szrj /* A subroutine for which BODY is part of the instruction being tested;
6538fd1498Szrj either the top-level pattern, or an element of a PARALLEL. The
6638fd1498Szrj instruction is known not to be a bare USE or CLOBBER. */
6738fd1498Szrj
6838fd1498Szrj static bool
deletable_insn_p_1(rtx body)6938fd1498Szrj deletable_insn_p_1 (rtx body)
7038fd1498Szrj {
7138fd1498Szrj switch (GET_CODE (body))
7238fd1498Szrj {
7338fd1498Szrj case PREFETCH:
7438fd1498Szrj case TRAP_IF:
7538fd1498Szrj /* The UNSPEC case was added here because the ia-64 claims that
7638fd1498Szrj USEs do not work after reload and generates UNSPECS rather
7738fd1498Szrj than USEs. Since dce is run after reload we need to avoid
7838fd1498Szrj deleting these even if they are dead. If it turns out that
7938fd1498Szrj USEs really do work after reload, the ia-64 should be
8038fd1498Szrj changed, and the UNSPEC case can be removed. */
8138fd1498Szrj case UNSPEC:
8238fd1498Szrj return false;
8338fd1498Szrj
8438fd1498Szrj default:
8538fd1498Szrj return !volatile_refs_p (body);
8638fd1498Szrj }
8738fd1498Szrj }
8838fd1498Szrj
8938fd1498Szrj
9038fd1498Szrj /* Return true if INSN is a normal instruction that can be deleted by
9138fd1498Szrj the DCE pass. */
9238fd1498Szrj
9338fd1498Szrj static bool
deletable_insn_p(rtx_insn * insn,bool fast,bitmap arg_stores)9438fd1498Szrj deletable_insn_p (rtx_insn *insn, bool fast, bitmap arg_stores)
9538fd1498Szrj {
9638fd1498Szrj rtx body, x;
9738fd1498Szrj int i;
9838fd1498Szrj df_ref def;
9938fd1498Szrj
10038fd1498Szrj if (CALL_P (insn)
10138fd1498Szrj /* We cannot delete calls inside of the recursive dce because
10238fd1498Szrj this may cause basic blocks to be deleted and this messes up
10338fd1498Szrj the rest of the stack of optimization passes. */
10438fd1498Szrj && (!df_in_progress)
10538fd1498Szrj /* We cannot delete pure or const sibling calls because it is
10638fd1498Szrj hard to see the result. */
10738fd1498Szrj && (!SIBLING_CALL_P (insn))
10838fd1498Szrj /* We can delete dead const or pure calls as long as they do not
10938fd1498Szrj infinite loop. */
11038fd1498Szrj && (RTL_CONST_OR_PURE_CALL_P (insn)
111*58e805e6Szrj && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn))
112*58e805e6Szrj /* Don't delete calls that may throw if we cannot do so. */
113*58e805e6Szrj && ((cfun->can_delete_dead_exceptions && can_alter_cfg)
114*58e805e6Szrj || insn_nothrow_p (insn)))
11538fd1498Szrj return find_call_stack_args (as_a <rtx_call_insn *> (insn), false,
11638fd1498Szrj fast, arg_stores);
11738fd1498Szrj
11838fd1498Szrj /* Don't delete jumps, notes and the like. */
11938fd1498Szrj if (!NONJUMP_INSN_P (insn))
12038fd1498Szrj return false;
12138fd1498Szrj
12238fd1498Szrj /* Don't delete insns that may throw if we cannot do so. */
12338fd1498Szrj if (!(cfun->can_delete_dead_exceptions && can_alter_cfg)
12438fd1498Szrj && !insn_nothrow_p (insn))
12538fd1498Szrj return false;
12638fd1498Szrj
12738fd1498Szrj /* If INSN sets a global_reg, leave it untouched. */
12838fd1498Szrj FOR_EACH_INSN_DEF (def, insn)
12938fd1498Szrj if (HARD_REGISTER_NUM_P (DF_REF_REGNO (def))
13038fd1498Szrj && global_regs[DF_REF_REGNO (def)])
13138fd1498Szrj return false;
13238fd1498Szrj /* Initialization of pseudo PIC register should never be removed. */
13338fd1498Szrj else if (DF_REF_REG (def) == pic_offset_table_rtx
13438fd1498Szrj && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
13538fd1498Szrj return false;
13638fd1498Szrj
13738fd1498Szrj /* Callee-save restores are needed. */
13838fd1498Szrj if (RTX_FRAME_RELATED_P (insn)
13938fd1498Szrj && crtl->shrink_wrapped_separate
14038fd1498Szrj && find_reg_note (insn, REG_CFA_RESTORE, NULL))
14138fd1498Szrj return false;
14238fd1498Szrj
14338fd1498Szrj body = PATTERN (insn);
14438fd1498Szrj switch (GET_CODE (body))
14538fd1498Szrj {
14638fd1498Szrj case USE:
14738fd1498Szrj case VAR_LOCATION:
14838fd1498Szrj return false;
14938fd1498Szrj
15038fd1498Szrj case CLOBBER:
15138fd1498Szrj if (fast)
15238fd1498Szrj {
15338fd1498Szrj /* A CLOBBER of a dead pseudo register serves no purpose.
15438fd1498Szrj That is not necessarily true for hard registers until
15538fd1498Szrj after reload. */
15638fd1498Szrj x = XEXP (body, 0);
15738fd1498Szrj return REG_P (x) && (!HARD_REGISTER_P (x) || reload_completed);
15838fd1498Szrj }
15938fd1498Szrj else
16038fd1498Szrj /* Because of the way that use-def chains are built, it is not
16138fd1498Szrj possible to tell if the clobber is dead because it can
16238fd1498Szrj never be the target of a use-def chain. */
16338fd1498Szrj return false;
16438fd1498Szrj
16538fd1498Szrj case PARALLEL:
16638fd1498Szrj for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
16738fd1498Szrj if (!deletable_insn_p_1 (XVECEXP (body, 0, i)))
16838fd1498Szrj return false;
16938fd1498Szrj return true;
17038fd1498Szrj
17138fd1498Szrj default:
17238fd1498Szrj return deletable_insn_p_1 (body);
17338fd1498Szrj }
17438fd1498Szrj }
17538fd1498Szrj
17638fd1498Szrj
17738fd1498Szrj /* Return true if INSN has been marked as needed. */
17838fd1498Szrj
17938fd1498Szrj static inline int
marked_insn_p(rtx_insn * insn)18038fd1498Szrj marked_insn_p (rtx_insn *insn)
18138fd1498Szrj {
18238fd1498Szrj /* Artificial defs are always needed and they do not have an insn.
18338fd1498Szrj We should never see them here. */
18438fd1498Szrj gcc_assert (insn);
18538fd1498Szrj return bitmap_bit_p (marked, INSN_UID (insn));
18638fd1498Szrj }
18738fd1498Szrj
18838fd1498Szrj
18938fd1498Szrj /* If INSN has not yet been marked as needed, mark it now, and add it to
19038fd1498Szrj the worklist. */
19138fd1498Szrj
19238fd1498Szrj static void
mark_insn(rtx_insn * insn,bool fast)19338fd1498Szrj mark_insn (rtx_insn *insn, bool fast)
19438fd1498Szrj {
19538fd1498Szrj if (!marked_insn_p (insn))
19638fd1498Szrj {
19738fd1498Szrj if (!fast)
19838fd1498Szrj worklist.safe_push (insn);
19938fd1498Szrj bitmap_set_bit (marked, INSN_UID (insn));
20038fd1498Szrj if (dump_file)
20138fd1498Szrj fprintf (dump_file, " Adding insn %d to worklist\n", INSN_UID (insn));
20238fd1498Szrj if (CALL_P (insn)
20338fd1498Szrj && !df_in_progress
20438fd1498Szrj && !SIBLING_CALL_P (insn)
20538fd1498Szrj && (RTL_CONST_OR_PURE_CALL_P (insn)
206*58e805e6Szrj && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn))
207*58e805e6Szrj && ((cfun->can_delete_dead_exceptions && can_alter_cfg)
208*58e805e6Szrj || insn_nothrow_p (insn)))
20938fd1498Szrj find_call_stack_args (as_a <rtx_call_insn *> (insn), true, fast, NULL);
21038fd1498Szrj }
21138fd1498Szrj }
21238fd1498Szrj
21338fd1498Szrj
21438fd1498Szrj /* A note_stores callback used by mark_nonreg_stores. DATA is the
21538fd1498Szrj instruction containing DEST. */
21638fd1498Szrj
21738fd1498Szrj static void
mark_nonreg_stores_1(rtx dest,const_rtx pattern,void * data)21838fd1498Szrj mark_nonreg_stores_1 (rtx dest, const_rtx pattern, void *data)
21938fd1498Szrj {
22038fd1498Szrj if (GET_CODE (pattern) != CLOBBER && !REG_P (dest))
22138fd1498Szrj mark_insn ((rtx_insn *) data, true);
22238fd1498Szrj }
22338fd1498Szrj
22438fd1498Szrj
22538fd1498Szrj /* A note_stores callback used by mark_nonreg_stores. DATA is the
22638fd1498Szrj instruction containing DEST. */
22738fd1498Szrj
22838fd1498Szrj static void
mark_nonreg_stores_2(rtx dest,const_rtx pattern,void * data)22938fd1498Szrj mark_nonreg_stores_2 (rtx dest, const_rtx pattern, void *data)
23038fd1498Szrj {
23138fd1498Szrj if (GET_CODE (pattern) != CLOBBER && !REG_P (dest))
23238fd1498Szrj mark_insn ((rtx_insn *) data, false);
23338fd1498Szrj }
23438fd1498Szrj
23538fd1498Szrj
23638fd1498Szrj /* Mark INSN if BODY stores to a non-register destination. */
23738fd1498Szrj
23838fd1498Szrj static void
mark_nonreg_stores(rtx body,rtx_insn * insn,bool fast)23938fd1498Szrj mark_nonreg_stores (rtx body, rtx_insn *insn, bool fast)
24038fd1498Szrj {
24138fd1498Szrj if (fast)
24238fd1498Szrj note_stores (body, mark_nonreg_stores_1, insn);
24338fd1498Szrj else
24438fd1498Szrj note_stores (body, mark_nonreg_stores_2, insn);
24538fd1498Szrj }
24638fd1498Szrj
24738fd1498Szrj
24838fd1498Szrj /* Return true if a store to SIZE bytes, starting OFF bytes from stack pointer,
24938fd1498Szrj is a call argument store, and clear corresponding bits from SP_BYTES
25038fd1498Szrj bitmap if it is. */
25138fd1498Szrj
25238fd1498Szrj 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)25338fd1498Szrj check_argument_store (HOST_WIDE_INT size, HOST_WIDE_INT off,
25438fd1498Szrj HOST_WIDE_INT min_sp_off, HOST_WIDE_INT max_sp_off,
25538fd1498Szrj bitmap sp_bytes)
25638fd1498Szrj {
25738fd1498Szrj HOST_WIDE_INT byte;
25838fd1498Szrj for (byte = off; byte < off + size; byte++)
25938fd1498Szrj {
26038fd1498Szrj if (byte < min_sp_off
26138fd1498Szrj || byte >= max_sp_off
26238fd1498Szrj || !bitmap_clear_bit (sp_bytes, byte - min_sp_off))
26338fd1498Szrj return false;
26438fd1498Szrj }
26538fd1498Szrj return true;
26638fd1498Szrj }
26738fd1498Szrj
26838fd1498Szrj
26938fd1498Szrj /* Try to find all stack stores of CALL_INSN arguments if
27038fd1498Szrj ACCUMULATE_OUTGOING_ARGS. If all stack stores have been found
27138fd1498Szrj and it is therefore safe to eliminate the call, return true,
27238fd1498Szrj otherwise return false. This function should be first called
27338fd1498Szrj with DO_MARK false, and only when the CALL_INSN is actually
27438fd1498Szrj going to be marked called again with DO_MARK true. */
27538fd1498Szrj
27638fd1498Szrj static bool
find_call_stack_args(rtx_call_insn * call_insn,bool do_mark,bool fast,bitmap arg_stores)27738fd1498Szrj find_call_stack_args (rtx_call_insn *call_insn, bool do_mark, bool fast,
27838fd1498Szrj bitmap arg_stores)
27938fd1498Szrj {
28038fd1498Szrj rtx p;
28138fd1498Szrj rtx_insn *insn, *prev_insn;
28238fd1498Szrj bool ret;
28338fd1498Szrj HOST_WIDE_INT min_sp_off, max_sp_off;
28438fd1498Szrj bitmap sp_bytes;
28538fd1498Szrj
28638fd1498Szrj gcc_assert (CALL_P (call_insn));
28738fd1498Szrj if (!ACCUMULATE_OUTGOING_ARGS)
28838fd1498Szrj return true;
28938fd1498Szrj
29038fd1498Szrj if (!do_mark)
29138fd1498Szrj {
29238fd1498Szrj gcc_assert (arg_stores);
29338fd1498Szrj bitmap_clear (arg_stores);
29438fd1498Szrj }
29538fd1498Szrj
29638fd1498Szrj min_sp_off = INTTYPE_MAXIMUM (HOST_WIDE_INT);
29738fd1498Szrj max_sp_off = 0;
29838fd1498Szrj
29938fd1498Szrj /* First determine the minimum and maximum offset from sp for
30038fd1498Szrj stored arguments. */
30138fd1498Szrj for (p = CALL_INSN_FUNCTION_USAGE (call_insn); p; p = XEXP (p, 1))
30238fd1498Szrj if (GET_CODE (XEXP (p, 0)) == USE
30338fd1498Szrj && MEM_P (XEXP (XEXP (p, 0), 0)))
30438fd1498Szrj {
30538fd1498Szrj rtx mem = XEXP (XEXP (p, 0), 0), addr;
30638fd1498Szrj HOST_WIDE_INT off = 0, size;
30738fd1498Szrj if (!MEM_SIZE_KNOWN_P (mem) || !MEM_SIZE (mem).is_constant (&size))
30838fd1498Szrj return false;
30938fd1498Szrj addr = XEXP (mem, 0);
31038fd1498Szrj if (GET_CODE (addr) == PLUS
31138fd1498Szrj && REG_P (XEXP (addr, 0))
31238fd1498Szrj && CONST_INT_P (XEXP (addr, 1)))
31338fd1498Szrj {
31438fd1498Szrj off = INTVAL (XEXP (addr, 1));
31538fd1498Szrj addr = XEXP (addr, 0);
31638fd1498Szrj }
31738fd1498Szrj if (addr != stack_pointer_rtx)
31838fd1498Szrj {
31938fd1498Szrj if (!REG_P (addr))
32038fd1498Szrj return false;
32138fd1498Szrj /* If not fast, use chains to see if addr wasn't set to
32238fd1498Szrj sp + offset. */
32338fd1498Szrj if (!fast)
32438fd1498Szrj {
32538fd1498Szrj df_ref use;
32638fd1498Szrj struct df_link *defs;
32738fd1498Szrj rtx set;
32838fd1498Szrj
32938fd1498Szrj FOR_EACH_INSN_USE (use, call_insn)
33038fd1498Szrj if (rtx_equal_p (addr, DF_REF_REG (use)))
33138fd1498Szrj break;
33238fd1498Szrj
33338fd1498Szrj if (use == NULL)
33438fd1498Szrj return false;
33538fd1498Szrj
33638fd1498Szrj for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
33738fd1498Szrj if (! DF_REF_IS_ARTIFICIAL (defs->ref))
33838fd1498Szrj break;
33938fd1498Szrj
34038fd1498Szrj if (defs == NULL)
34138fd1498Szrj return false;
34238fd1498Szrj
34338fd1498Szrj set = single_set (DF_REF_INSN (defs->ref));
34438fd1498Szrj if (!set)
34538fd1498Szrj return false;
34638fd1498Szrj
34738fd1498Szrj if (GET_CODE (SET_SRC (set)) != PLUS
34838fd1498Szrj || XEXP (SET_SRC (set), 0) != stack_pointer_rtx
34938fd1498Szrj || !CONST_INT_P (XEXP (SET_SRC (set), 1)))
35038fd1498Szrj return false;
35138fd1498Szrj
35238fd1498Szrj off += INTVAL (XEXP (SET_SRC (set), 1));
35338fd1498Szrj }
35438fd1498Szrj else
35538fd1498Szrj return false;
35638fd1498Szrj }
35738fd1498Szrj min_sp_off = MIN (min_sp_off, off);
35838fd1498Szrj max_sp_off = MAX (max_sp_off, off + size);
35938fd1498Szrj }
36038fd1498Szrj
36138fd1498Szrj if (min_sp_off >= max_sp_off)
36238fd1498Szrj return true;
36338fd1498Szrj sp_bytes = BITMAP_ALLOC (NULL);
36438fd1498Szrj
36538fd1498Szrj /* Set bits in SP_BYTES bitmap for bytes relative to sp + min_sp_off
36638fd1498Szrj which contain arguments. Checking has been done in the previous
36738fd1498Szrj loop. */
36838fd1498Szrj for (p = CALL_INSN_FUNCTION_USAGE (call_insn); p; p = XEXP (p, 1))
36938fd1498Szrj if (GET_CODE (XEXP (p, 0)) == USE
37038fd1498Szrj && MEM_P (XEXP (XEXP (p, 0), 0)))
37138fd1498Szrj {
37238fd1498Szrj rtx mem = XEXP (XEXP (p, 0), 0), addr;
37338fd1498Szrj HOST_WIDE_INT off = 0, byte, size;
37438fd1498Szrj /* Checked in the previous iteration. */
37538fd1498Szrj size = MEM_SIZE (mem).to_constant ();
37638fd1498Szrj addr = XEXP (mem, 0);
37738fd1498Szrj if (GET_CODE (addr) == PLUS
37838fd1498Szrj && REG_P (XEXP (addr, 0))
37938fd1498Szrj && CONST_INT_P (XEXP (addr, 1)))
38038fd1498Szrj {
38138fd1498Szrj off = INTVAL (XEXP (addr, 1));
38238fd1498Szrj addr = XEXP (addr, 0);
38338fd1498Szrj }
38438fd1498Szrj if (addr != stack_pointer_rtx)
38538fd1498Szrj {
38638fd1498Szrj df_ref use;
38738fd1498Szrj struct df_link *defs;
38838fd1498Szrj rtx set;
38938fd1498Szrj
39038fd1498Szrj FOR_EACH_INSN_USE (use, call_insn)
39138fd1498Szrj if (rtx_equal_p (addr, DF_REF_REG (use)))
39238fd1498Szrj break;
39338fd1498Szrj
39438fd1498Szrj for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
39538fd1498Szrj if (! DF_REF_IS_ARTIFICIAL (defs->ref))
39638fd1498Szrj break;
39738fd1498Szrj
39838fd1498Szrj set = single_set (DF_REF_INSN (defs->ref));
39938fd1498Szrj off += INTVAL (XEXP (SET_SRC (set), 1));
40038fd1498Szrj }
40138fd1498Szrj for (byte = off; byte < off + size; byte++)
40238fd1498Szrj {
40338fd1498Szrj if (!bitmap_set_bit (sp_bytes, byte - min_sp_off))
40438fd1498Szrj gcc_unreachable ();
40538fd1498Szrj }
40638fd1498Szrj }
40738fd1498Szrj
40838fd1498Szrj /* Walk backwards, looking for argument stores. The search stops
40938fd1498Szrj when seeing another call, sp adjustment or memory store other than
41038fd1498Szrj argument store. */
41138fd1498Szrj ret = false;
41238fd1498Szrj for (insn = PREV_INSN (call_insn); insn; insn = prev_insn)
41338fd1498Szrj {
41438fd1498Szrj rtx set, mem, addr;
41538fd1498Szrj HOST_WIDE_INT off;
41638fd1498Szrj
41738fd1498Szrj if (insn == BB_HEAD (BLOCK_FOR_INSN (call_insn)))
41838fd1498Szrj prev_insn = NULL;
41938fd1498Szrj else
42038fd1498Szrj prev_insn = PREV_INSN (insn);
42138fd1498Szrj
42238fd1498Szrj if (CALL_P (insn))
42338fd1498Szrj break;
42438fd1498Szrj
42538fd1498Szrj if (!NONDEBUG_INSN_P (insn))
42638fd1498Szrj continue;
42738fd1498Szrj
42838fd1498Szrj set = single_set (insn);
42938fd1498Szrj if (!set || SET_DEST (set) == stack_pointer_rtx)
43038fd1498Szrj break;
43138fd1498Szrj
43238fd1498Szrj if (!MEM_P (SET_DEST (set)))
43338fd1498Szrj continue;
43438fd1498Szrj
43538fd1498Szrj mem = SET_DEST (set);
43638fd1498Szrj addr = XEXP (mem, 0);
43738fd1498Szrj off = 0;
43838fd1498Szrj if (GET_CODE (addr) == PLUS
43938fd1498Szrj && REG_P (XEXP (addr, 0))
44038fd1498Szrj && CONST_INT_P (XEXP (addr, 1)))
44138fd1498Szrj {
44238fd1498Szrj off = INTVAL (XEXP (addr, 1));
44338fd1498Szrj addr = XEXP (addr, 0);
44438fd1498Szrj }
44538fd1498Szrj if (addr != stack_pointer_rtx)
44638fd1498Szrj {
44738fd1498Szrj if (!REG_P (addr))
44838fd1498Szrj break;
44938fd1498Szrj if (!fast)
45038fd1498Szrj {
45138fd1498Szrj df_ref use;
45238fd1498Szrj struct df_link *defs;
45338fd1498Szrj rtx set;
45438fd1498Szrj
45538fd1498Szrj FOR_EACH_INSN_USE (use, insn)
45638fd1498Szrj if (rtx_equal_p (addr, DF_REF_REG (use)))
45738fd1498Szrj break;
45838fd1498Szrj
45938fd1498Szrj if (use == NULL)
46038fd1498Szrj break;
46138fd1498Szrj
46238fd1498Szrj for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
46338fd1498Szrj if (! DF_REF_IS_ARTIFICIAL (defs->ref))
46438fd1498Szrj break;
46538fd1498Szrj
46638fd1498Szrj if (defs == NULL)
46738fd1498Szrj break;
46838fd1498Szrj
46938fd1498Szrj set = single_set (DF_REF_INSN (defs->ref));
47038fd1498Szrj if (!set)
47138fd1498Szrj break;
47238fd1498Szrj
47338fd1498Szrj if (GET_CODE (SET_SRC (set)) != PLUS
47438fd1498Szrj || XEXP (SET_SRC (set), 0) != stack_pointer_rtx
47538fd1498Szrj || !CONST_INT_P (XEXP (SET_SRC (set), 1)))
47638fd1498Szrj break;
47738fd1498Szrj
47838fd1498Szrj off += INTVAL (XEXP (SET_SRC (set), 1));
47938fd1498Szrj }
48038fd1498Szrj else
48138fd1498Szrj break;
48238fd1498Szrj }
48338fd1498Szrj
48438fd1498Szrj HOST_WIDE_INT size;
48538fd1498Szrj if (!MEM_SIZE_KNOWN_P (mem)
48638fd1498Szrj || !MEM_SIZE (mem).is_constant (&size)
48738fd1498Szrj || !check_argument_store (size, off, min_sp_off,
48838fd1498Szrj max_sp_off, sp_bytes))
48938fd1498Szrj break;
49038fd1498Szrj
49138fd1498Szrj if (!deletable_insn_p (insn, fast, NULL))
49238fd1498Szrj break;
49338fd1498Szrj
49438fd1498Szrj if (do_mark)
49538fd1498Szrj mark_insn (insn, fast);
49638fd1498Szrj else
49738fd1498Szrj bitmap_set_bit (arg_stores, INSN_UID (insn));
49838fd1498Szrj
49938fd1498Szrj if (bitmap_empty_p (sp_bytes))
50038fd1498Szrj {
50138fd1498Szrj ret = true;
50238fd1498Szrj break;
50338fd1498Szrj }
50438fd1498Szrj }
50538fd1498Szrj
50638fd1498Szrj BITMAP_FREE (sp_bytes);
50738fd1498Szrj if (!ret && arg_stores)
50838fd1498Szrj bitmap_clear (arg_stores);
50938fd1498Szrj
51038fd1498Szrj return ret;
51138fd1498Szrj }
51238fd1498Szrj
51338fd1498Szrj
51438fd1498Szrj /* Remove all REG_EQUAL and REG_EQUIV notes referring to the registers INSN
51538fd1498Szrj writes to. */
51638fd1498Szrj
51738fd1498Szrj static void
remove_reg_equal_equiv_notes_for_defs(rtx_insn * insn)51838fd1498Szrj remove_reg_equal_equiv_notes_for_defs (rtx_insn *insn)
51938fd1498Szrj {
52038fd1498Szrj df_ref def;
52138fd1498Szrj
52238fd1498Szrj FOR_EACH_INSN_DEF (def, insn)
52338fd1498Szrj remove_reg_equal_equiv_notes_for_regno (DF_REF_REGNO (def));
52438fd1498Szrj }
52538fd1498Szrj
52638fd1498Szrj /* Scan all BBs for debug insns and reset those that reference values
52738fd1498Szrj defined in unmarked insns. */
52838fd1498Szrj
52938fd1498Szrj static void
reset_unmarked_insns_debug_uses(void)53038fd1498Szrj reset_unmarked_insns_debug_uses (void)
53138fd1498Szrj {
53238fd1498Szrj basic_block bb;
53338fd1498Szrj rtx_insn *insn, *next;
53438fd1498Szrj
53538fd1498Szrj FOR_EACH_BB_REVERSE_FN (bb, cfun)
53638fd1498Szrj FOR_BB_INSNS_REVERSE_SAFE (bb, insn, next)
53738fd1498Szrj if (DEBUG_INSN_P (insn))
53838fd1498Szrj {
53938fd1498Szrj df_ref use;
54038fd1498Szrj
54138fd1498Szrj FOR_EACH_INSN_USE (use, insn)
54238fd1498Szrj {
54338fd1498Szrj struct df_link *defs;
54438fd1498Szrj for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
54538fd1498Szrj {
54638fd1498Szrj rtx_insn *ref_insn;
54738fd1498Szrj if (DF_REF_IS_ARTIFICIAL (defs->ref))
54838fd1498Szrj continue;
54938fd1498Szrj ref_insn = DF_REF_INSN (defs->ref);
55038fd1498Szrj if (!marked_insn_p (ref_insn))
55138fd1498Szrj break;
55238fd1498Szrj }
55338fd1498Szrj if (!defs)
55438fd1498Szrj continue;
55538fd1498Szrj /* ??? FIXME could we propagate the values assigned to
55638fd1498Szrj each of the DEFs? */
55738fd1498Szrj INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
55838fd1498Szrj df_insn_rescan_debug_internal (insn);
55938fd1498Szrj break;
56038fd1498Szrj }
56138fd1498Szrj }
56238fd1498Szrj }
56338fd1498Szrj
56438fd1498Szrj /* Delete every instruction that hasn't been marked. */
56538fd1498Szrj
56638fd1498Szrj static void
delete_unmarked_insns(void)56738fd1498Szrj delete_unmarked_insns (void)
56838fd1498Szrj {
56938fd1498Szrj basic_block bb;
57038fd1498Szrj rtx_insn *insn, *next;
57138fd1498Szrj bool must_clean = false;
57238fd1498Szrj
57338fd1498Szrj FOR_EACH_BB_REVERSE_FN (bb, cfun)
57438fd1498Szrj FOR_BB_INSNS_REVERSE_SAFE (bb, insn, next)
57538fd1498Szrj if (NONDEBUG_INSN_P (insn))
57638fd1498Szrj {
57738fd1498Szrj rtx turn_into_use = NULL_RTX;
57838fd1498Szrj
57938fd1498Szrj /* Always delete no-op moves. */
580*58e805e6Szrj if (noop_move_p (insn)
581*58e805e6Szrj /* Unless the no-op move can throw and we are not allowed
582*58e805e6Szrj to alter cfg. */
583*58e805e6Szrj && (!cfun->can_throw_non_call_exceptions
584*58e805e6Szrj || (cfun->can_delete_dead_exceptions && can_alter_cfg)
585*58e805e6Szrj || insn_nothrow_p (insn)))
58638fd1498Szrj {
58738fd1498Szrj if (RTX_FRAME_RELATED_P (insn))
58838fd1498Szrj turn_into_use
58938fd1498Szrj = find_reg_note (insn, REG_CFA_RESTORE, NULL);
59038fd1498Szrj if (turn_into_use && REG_P (XEXP (turn_into_use, 0)))
59138fd1498Szrj turn_into_use = XEXP (turn_into_use, 0);
59238fd1498Szrj else
59338fd1498Szrj turn_into_use = NULL_RTX;
59438fd1498Szrj }
59538fd1498Szrj
59638fd1498Szrj /* Otherwise rely only on the DCE algorithm. */
59738fd1498Szrj else if (marked_insn_p (insn))
59838fd1498Szrj continue;
59938fd1498Szrj
60038fd1498Szrj /* Beware that reaching a dbg counter limit here can result
60138fd1498Szrj in miscompiled file. This occurs when a group of insns
60238fd1498Szrj must be deleted together, typically because the kept insn
60338fd1498Szrj depends on the output from the deleted insn. Deleting
60438fd1498Szrj this insns in reverse order (both at the bb level and
60538fd1498Szrj when looking at the blocks) minimizes this, but does not
60638fd1498Szrj eliminate it, since it is possible for the using insn to
60738fd1498Szrj be top of a block and the producer to be at the bottom of
60838fd1498Szrj the block. However, in most cases this will only result
60938fd1498Szrj in an uninitialized use of an insn that is dead anyway.
61038fd1498Szrj
61138fd1498Szrj However, there is one rare case that will cause a
61238fd1498Szrj miscompile: deletion of non-looping pure and constant
61338fd1498Szrj calls on a machine where ACCUMULATE_OUTGOING_ARGS is true.
61438fd1498Szrj In this case it is possible to remove the call, but leave
61538fd1498Szrj the argument pushes to the stack. Because of the changes
61638fd1498Szrj to the stack pointer, this will almost always lead to a
61738fd1498Szrj miscompile. */
61838fd1498Szrj if (!dbg_cnt (dce))
61938fd1498Szrj continue;
62038fd1498Szrj
62138fd1498Szrj if (dump_file)
62238fd1498Szrj fprintf (dump_file, "DCE: Deleting insn %d\n", INSN_UID (insn));
62338fd1498Szrj
62438fd1498Szrj /* Before we delete the insn we have to remove the REG_EQUAL notes
62538fd1498Szrj for the destination regs in order to avoid dangling notes. */
62638fd1498Szrj remove_reg_equal_equiv_notes_for_defs (insn);
62738fd1498Szrj
62838fd1498Szrj if (turn_into_use)
62938fd1498Szrj {
63038fd1498Szrj /* Don't remove frame related noop moves if they cary
63138fd1498Szrj REG_CFA_RESTORE note, while we don't need to emit any code,
63238fd1498Szrj we need it to emit the CFI restore note. */
63338fd1498Szrj PATTERN (insn)
63438fd1498Szrj = gen_rtx_USE (GET_MODE (turn_into_use), turn_into_use);
63538fd1498Szrj INSN_CODE (insn) = -1;
63638fd1498Szrj df_insn_rescan (insn);
63738fd1498Szrj }
63838fd1498Szrj else
63938fd1498Szrj /* Now delete the insn. */
640*58e805e6Szrj must_clean |= delete_insn_and_edges (insn);
64138fd1498Szrj }
64238fd1498Szrj
64338fd1498Szrj /* Deleted a pure or const call. */
64438fd1498Szrj if (must_clean)
645*58e805e6Szrj {
64638fd1498Szrj delete_unreachable_blocks ();
647*58e805e6Szrj free_dominance_info (CDI_DOMINATORS);
648*58e805e6Szrj }
64938fd1498Szrj }
65038fd1498Szrj
65138fd1498Szrj
65238fd1498Szrj /* Go through the instructions and mark those whose necessity is not
65338fd1498Szrj dependent on inter-instruction information. Make sure all other
65438fd1498Szrj instructions are not marked. */
65538fd1498Szrj
65638fd1498Szrj static void
prescan_insns_for_dce(bool fast)65738fd1498Szrj prescan_insns_for_dce (bool fast)
65838fd1498Szrj {
65938fd1498Szrj basic_block bb;
66038fd1498Szrj rtx_insn *insn, *prev;
66138fd1498Szrj bitmap arg_stores = NULL;
66238fd1498Szrj
66338fd1498Szrj if (dump_file)
66438fd1498Szrj fprintf (dump_file, "Finding needed instructions:\n");
66538fd1498Szrj
66638fd1498Szrj if (!df_in_progress && ACCUMULATE_OUTGOING_ARGS)
66738fd1498Szrj arg_stores = BITMAP_ALLOC (NULL);
66838fd1498Szrj
66938fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
67038fd1498Szrj {
67138fd1498Szrj FOR_BB_INSNS_REVERSE_SAFE (bb, insn, prev)
67238fd1498Szrj if (NONDEBUG_INSN_P (insn))
67338fd1498Szrj {
67438fd1498Szrj /* Don't mark argument stores now. They will be marked
67538fd1498Szrj if needed when the associated CALL is marked. */
67638fd1498Szrj if (arg_stores && bitmap_bit_p (arg_stores, INSN_UID (insn)))
67738fd1498Szrj continue;
67838fd1498Szrj if (deletable_insn_p (insn, fast, arg_stores))
67938fd1498Szrj mark_nonreg_stores (PATTERN (insn), insn, fast);
68038fd1498Szrj else
68138fd1498Szrj mark_insn (insn, fast);
68238fd1498Szrj }
68338fd1498Szrj /* find_call_stack_args only looks at argument stores in the
68438fd1498Szrj same bb. */
68538fd1498Szrj if (arg_stores)
68638fd1498Szrj bitmap_clear (arg_stores);
68738fd1498Szrj }
68838fd1498Szrj
68938fd1498Szrj if (arg_stores)
69038fd1498Szrj BITMAP_FREE (arg_stores);
69138fd1498Szrj
69238fd1498Szrj if (dump_file)
69338fd1498Szrj fprintf (dump_file, "Finished finding needed instructions:\n");
69438fd1498Szrj }
69538fd1498Szrj
69638fd1498Szrj
69738fd1498Szrj /* UD-based DSE routines. */
69838fd1498Szrj
69938fd1498Szrj /* Mark instructions that define artificially-used registers, such as
70038fd1498Szrj the frame pointer and the stack pointer. */
70138fd1498Szrj
70238fd1498Szrj static void
mark_artificial_uses(void)70338fd1498Szrj mark_artificial_uses (void)
70438fd1498Szrj {
70538fd1498Szrj basic_block bb;
70638fd1498Szrj struct df_link *defs;
70738fd1498Szrj df_ref use;
70838fd1498Szrj
70938fd1498Szrj FOR_ALL_BB_FN (bb, cfun)
71038fd1498Szrj FOR_EACH_ARTIFICIAL_USE (use, bb->index)
71138fd1498Szrj for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
71238fd1498Szrj if (!DF_REF_IS_ARTIFICIAL (defs->ref))
71338fd1498Szrj mark_insn (DF_REF_INSN (defs->ref), false);
71438fd1498Szrj }
71538fd1498Szrj
71638fd1498Szrj
71738fd1498Szrj /* Mark every instruction that defines a register value that INSN uses. */
71838fd1498Szrj
71938fd1498Szrj static void
mark_reg_dependencies(rtx_insn * insn)72038fd1498Szrj mark_reg_dependencies (rtx_insn *insn)
72138fd1498Szrj {
72238fd1498Szrj struct df_link *defs;
72338fd1498Szrj df_ref use;
72438fd1498Szrj
72538fd1498Szrj if (DEBUG_INSN_P (insn))
72638fd1498Szrj return;
72738fd1498Szrj
72838fd1498Szrj FOR_EACH_INSN_USE (use, insn)
72938fd1498Szrj {
73038fd1498Szrj if (dump_file)
73138fd1498Szrj {
73238fd1498Szrj fprintf (dump_file, "Processing use of ");
73338fd1498Szrj print_simple_rtl (dump_file, DF_REF_REG (use));
73438fd1498Szrj fprintf (dump_file, " in insn %d:\n", INSN_UID (insn));
73538fd1498Szrj }
73638fd1498Szrj for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
73738fd1498Szrj if (! DF_REF_IS_ARTIFICIAL (defs->ref))
73838fd1498Szrj mark_insn (DF_REF_INSN (defs->ref), false);
73938fd1498Szrj }
74038fd1498Szrj }
74138fd1498Szrj
74238fd1498Szrj
74338fd1498Szrj /* Initialize global variables for a new DCE pass. */
74438fd1498Szrj
74538fd1498Szrj static void
init_dce(bool fast)74638fd1498Szrj init_dce (bool fast)
74738fd1498Szrj {
74838fd1498Szrj if (!df_in_progress)
74938fd1498Szrj {
75038fd1498Szrj if (!fast)
75138fd1498Szrj {
75238fd1498Szrj df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
75338fd1498Szrj df_chain_add_problem (DF_UD_CHAIN);
75438fd1498Szrj }
75538fd1498Szrj df_analyze ();
75638fd1498Szrj }
75738fd1498Szrj
75838fd1498Szrj if (dump_file)
75938fd1498Szrj df_dump (dump_file);
76038fd1498Szrj
76138fd1498Szrj if (fast)
76238fd1498Szrj {
76338fd1498Szrj bitmap_obstack_initialize (&dce_blocks_bitmap_obstack);
76438fd1498Szrj bitmap_obstack_initialize (&dce_tmp_bitmap_obstack);
76538fd1498Szrj can_alter_cfg = false;
76638fd1498Szrj }
76738fd1498Szrj else
76838fd1498Szrj can_alter_cfg = true;
76938fd1498Szrj
77038fd1498Szrj marked = sbitmap_alloc (get_max_uid () + 1);
77138fd1498Szrj bitmap_clear (marked);
77238fd1498Szrj }
77338fd1498Szrj
77438fd1498Szrj
77538fd1498Szrj /* Free the data allocated by init_dce. */
77638fd1498Szrj
77738fd1498Szrj static void
fini_dce(bool fast)77838fd1498Szrj fini_dce (bool fast)
77938fd1498Szrj {
78038fd1498Szrj sbitmap_free (marked);
78138fd1498Szrj
78238fd1498Szrj if (fast)
78338fd1498Szrj {
78438fd1498Szrj bitmap_obstack_release (&dce_blocks_bitmap_obstack);
78538fd1498Szrj bitmap_obstack_release (&dce_tmp_bitmap_obstack);
78638fd1498Szrj }
78738fd1498Szrj }
78838fd1498Szrj
78938fd1498Szrj
79038fd1498Szrj /* UD-chain based DCE. */
79138fd1498Szrj
79238fd1498Szrj static unsigned int
rest_of_handle_ud_dce(void)79338fd1498Szrj rest_of_handle_ud_dce (void)
79438fd1498Szrj {
79538fd1498Szrj rtx_insn *insn;
79638fd1498Szrj
79738fd1498Szrj init_dce (false);
79838fd1498Szrj
79938fd1498Szrj prescan_insns_for_dce (false);
80038fd1498Szrj mark_artificial_uses ();
80138fd1498Szrj while (worklist.length () > 0)
80238fd1498Szrj {
80338fd1498Szrj insn = worklist.pop ();
80438fd1498Szrj mark_reg_dependencies (insn);
80538fd1498Szrj }
80638fd1498Szrj worklist.release ();
80738fd1498Szrj
80838fd1498Szrj if (MAY_HAVE_DEBUG_BIND_INSNS)
80938fd1498Szrj reset_unmarked_insns_debug_uses ();
81038fd1498Szrj
81138fd1498Szrj /* Before any insns are deleted, we must remove the chains since
81238fd1498Szrj they are not bidirectional. */
81338fd1498Szrj df_remove_problem (df_chain);
81438fd1498Szrj delete_unmarked_insns ();
81538fd1498Szrj
81638fd1498Szrj fini_dce (false);
81738fd1498Szrj return 0;
81838fd1498Szrj }
81938fd1498Szrj
82038fd1498Szrj
82138fd1498Szrj namespace {
82238fd1498Szrj
82338fd1498Szrj const pass_data pass_data_ud_rtl_dce =
82438fd1498Szrj {
82538fd1498Szrj RTL_PASS, /* type */
82638fd1498Szrj "ud_dce", /* name */
82738fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
82838fd1498Szrj TV_DCE, /* tv_id */
82938fd1498Szrj 0, /* properties_required */
83038fd1498Szrj 0, /* properties_provided */
83138fd1498Szrj 0, /* properties_destroyed */
83238fd1498Szrj 0, /* todo_flags_start */
83338fd1498Szrj TODO_df_finish, /* todo_flags_finish */
83438fd1498Szrj };
83538fd1498Szrj
83638fd1498Szrj class pass_ud_rtl_dce : public rtl_opt_pass
83738fd1498Szrj {
83838fd1498Szrj public:
pass_ud_rtl_dce(gcc::context * ctxt)83938fd1498Szrj pass_ud_rtl_dce (gcc::context *ctxt)
84038fd1498Szrj : rtl_opt_pass (pass_data_ud_rtl_dce, ctxt)
84138fd1498Szrj {}
84238fd1498Szrj
84338fd1498Szrj /* opt_pass methods: */
gate(function *)84438fd1498Szrj virtual bool gate (function *)
84538fd1498Szrj {
84638fd1498Szrj return optimize > 1 && flag_dce && dbg_cnt (dce_ud);
84738fd1498Szrj }
84838fd1498Szrj
execute(function *)84938fd1498Szrj virtual unsigned int execute (function *)
85038fd1498Szrj {
85138fd1498Szrj return rest_of_handle_ud_dce ();
85238fd1498Szrj }
85338fd1498Szrj
85438fd1498Szrj }; // class pass_ud_rtl_dce
85538fd1498Szrj
85638fd1498Szrj } // anon namespace
85738fd1498Szrj
85838fd1498Szrj rtl_opt_pass *
make_pass_ud_rtl_dce(gcc::context * ctxt)85938fd1498Szrj make_pass_ud_rtl_dce (gcc::context *ctxt)
86038fd1498Szrj {
86138fd1498Szrj return new pass_ud_rtl_dce (ctxt);
86238fd1498Szrj }
86338fd1498Szrj
86438fd1498Szrj
86538fd1498Szrj /* -------------------------------------------------------------------------
86638fd1498Szrj Fast DCE functions
86738fd1498Szrj ------------------------------------------------------------------------- */
86838fd1498Szrj
86938fd1498Szrj /* Process basic block BB. Return true if the live_in set has
87038fd1498Szrj changed. REDO_OUT is true if the info at the bottom of the block
87138fd1498Szrj needs to be recalculated before starting. AU is the proper set of
87238fd1498Szrj artificial uses. Track global substitution of uses of dead pseudos
87338fd1498Szrj in debug insns using GLOBAL_DEBUG. */
87438fd1498Szrj
87538fd1498Szrj static bool
word_dce_process_block(basic_block bb,bool redo_out,struct dead_debug_global * global_debug)87638fd1498Szrj word_dce_process_block (basic_block bb, bool redo_out,
87738fd1498Szrj struct dead_debug_global *global_debug)
87838fd1498Szrj {
87938fd1498Szrj bitmap local_live = BITMAP_ALLOC (&dce_tmp_bitmap_obstack);
88038fd1498Szrj rtx_insn *insn;
88138fd1498Szrj bool block_changed;
88238fd1498Szrj struct dead_debug_local debug;
88338fd1498Szrj
88438fd1498Szrj if (redo_out)
88538fd1498Szrj {
88638fd1498Szrj /* Need to redo the live_out set of this block if when one of
88738fd1498Szrj the succs of this block has had a change in it live in
88838fd1498Szrj set. */
88938fd1498Szrj edge e;
89038fd1498Szrj edge_iterator ei;
89138fd1498Szrj df_confluence_function_n con_fun_n = df_word_lr->problem->con_fun_n;
89238fd1498Szrj bitmap_clear (DF_WORD_LR_OUT (bb));
89338fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
89438fd1498Szrj (*con_fun_n) (e);
89538fd1498Szrj }
89638fd1498Szrj
89738fd1498Szrj if (dump_file)
89838fd1498Szrj {
89938fd1498Szrj fprintf (dump_file, "processing block %d live out = ", bb->index);
90038fd1498Szrj df_print_word_regset (dump_file, DF_WORD_LR_OUT (bb));
90138fd1498Szrj }
90238fd1498Szrj
90338fd1498Szrj bitmap_copy (local_live, DF_WORD_LR_OUT (bb));
90438fd1498Szrj dead_debug_local_init (&debug, NULL, global_debug);
90538fd1498Szrj
90638fd1498Szrj FOR_BB_INSNS_REVERSE (bb, insn)
90738fd1498Szrj if (DEBUG_INSN_P (insn))
90838fd1498Szrj {
90938fd1498Szrj df_ref use;
91038fd1498Szrj FOR_EACH_INSN_USE (use, insn)
91138fd1498Szrj if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER
91238fd1498Szrj && known_eq (GET_MODE_SIZE (GET_MODE (DF_REF_REAL_REG (use))),
91338fd1498Szrj 2 * UNITS_PER_WORD)
91438fd1498Szrj && !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (use))
91538fd1498Szrj && !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (use) + 1))
91638fd1498Szrj dead_debug_add (&debug, use, DF_REF_REGNO (use));
91738fd1498Szrj }
91838fd1498Szrj else if (INSN_P (insn))
91938fd1498Szrj {
92038fd1498Szrj bool any_changed;
92138fd1498Szrj
92238fd1498Szrj /* No matter if the instruction is needed or not, we remove
92338fd1498Szrj any regno in the defs from the live set. */
92438fd1498Szrj any_changed = df_word_lr_simulate_defs (insn, local_live);
92538fd1498Szrj if (any_changed)
92638fd1498Szrj mark_insn (insn, true);
92738fd1498Szrj
92838fd1498Szrj /* On the other hand, we do not allow the dead uses to set
92938fd1498Szrj anything in local_live. */
93038fd1498Szrj if (marked_insn_p (insn))
93138fd1498Szrj df_word_lr_simulate_uses (insn, local_live);
93238fd1498Szrj
93338fd1498Szrj /* Insert debug temps for dead REGs used in subsequent debug
93438fd1498Szrj insns. We may have to emit a debug temp even if the insn
93538fd1498Szrj was marked, in case the debug use was after the point of
93638fd1498Szrj death. */
93738fd1498Szrj if (debug.used && !bitmap_empty_p (debug.used))
93838fd1498Szrj {
93938fd1498Szrj df_ref def;
94038fd1498Szrj
94138fd1498Szrj FOR_EACH_INSN_DEF (def, insn)
94238fd1498Szrj dead_debug_insert_temp (&debug, DF_REF_REGNO (def), insn,
94338fd1498Szrj marked_insn_p (insn)
94438fd1498Szrj && !control_flow_insn_p (insn)
94538fd1498Szrj ? DEBUG_TEMP_AFTER_WITH_REG_FORCE
94638fd1498Szrj : DEBUG_TEMP_BEFORE_WITH_VALUE);
94738fd1498Szrj }
94838fd1498Szrj
94938fd1498Szrj if (dump_file)
95038fd1498Szrj {
95138fd1498Szrj fprintf (dump_file, "finished processing insn %d live out = ",
95238fd1498Szrj INSN_UID (insn));
95338fd1498Szrj df_print_word_regset (dump_file, local_live);
95438fd1498Szrj }
95538fd1498Szrj }
95638fd1498Szrj
95738fd1498Szrj block_changed = !bitmap_equal_p (local_live, DF_WORD_LR_IN (bb));
95838fd1498Szrj if (block_changed)
95938fd1498Szrj bitmap_copy (DF_WORD_LR_IN (bb), local_live);
96038fd1498Szrj
96138fd1498Szrj dead_debug_local_finish (&debug, NULL);
96238fd1498Szrj BITMAP_FREE (local_live);
96338fd1498Szrj return block_changed;
96438fd1498Szrj }
96538fd1498Szrj
96638fd1498Szrj
96738fd1498Szrj /* Process basic block BB. Return true if the live_in set has
96838fd1498Szrj changed. REDO_OUT is true if the info at the bottom of the block
96938fd1498Szrj needs to be recalculated before starting. AU is the proper set of
97038fd1498Szrj artificial uses. Track global substitution of uses of dead pseudos
97138fd1498Szrj in debug insns using GLOBAL_DEBUG. */
97238fd1498Szrj
97338fd1498Szrj static bool
dce_process_block(basic_block bb,bool redo_out,bitmap au,struct dead_debug_global * global_debug)97438fd1498Szrj dce_process_block (basic_block bb, bool redo_out, bitmap au,
97538fd1498Szrj struct dead_debug_global *global_debug)
97638fd1498Szrj {
97738fd1498Szrj bitmap local_live = BITMAP_ALLOC (&dce_tmp_bitmap_obstack);
97838fd1498Szrj rtx_insn *insn;
97938fd1498Szrj bool block_changed;
98038fd1498Szrj df_ref def;
98138fd1498Szrj struct dead_debug_local debug;
98238fd1498Szrj
98338fd1498Szrj if (redo_out)
98438fd1498Szrj {
98538fd1498Szrj /* Need to redo the live_out set of this block if when one of
98638fd1498Szrj the succs of this block has had a change in it live in
98738fd1498Szrj set. */
98838fd1498Szrj edge e;
98938fd1498Szrj edge_iterator ei;
99038fd1498Szrj df_confluence_function_n con_fun_n = df_lr->problem->con_fun_n;
99138fd1498Szrj bitmap_clear (DF_LR_OUT (bb));
99238fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
99338fd1498Szrj (*con_fun_n) (e);
99438fd1498Szrj }
99538fd1498Szrj
99638fd1498Szrj if (dump_file)
99738fd1498Szrj {
99838fd1498Szrj fprintf (dump_file, "processing block %d lr out = ", bb->index);
99938fd1498Szrj df_print_regset (dump_file, DF_LR_OUT (bb));
100038fd1498Szrj }
100138fd1498Szrj
100238fd1498Szrj bitmap_copy (local_live, DF_LR_OUT (bb));
100338fd1498Szrj
100438fd1498Szrj df_simulate_initialize_backwards (bb, local_live);
100538fd1498Szrj dead_debug_local_init (&debug, NULL, global_debug);
100638fd1498Szrj
100738fd1498Szrj FOR_BB_INSNS_REVERSE (bb, insn)
100838fd1498Szrj if (DEBUG_INSN_P (insn))
100938fd1498Szrj {
101038fd1498Szrj df_ref use;
101138fd1498Szrj FOR_EACH_INSN_USE (use, insn)
101238fd1498Szrj if (!bitmap_bit_p (local_live, DF_REF_REGNO (use))
101338fd1498Szrj && !bitmap_bit_p (au, DF_REF_REGNO (use)))
101438fd1498Szrj dead_debug_add (&debug, use, DF_REF_REGNO (use));
101538fd1498Szrj }
101638fd1498Szrj else if (INSN_P (insn))
101738fd1498Szrj {
101838fd1498Szrj bool needed = marked_insn_p (insn);
101938fd1498Szrj
102038fd1498Szrj /* The insn is needed if there is someone who uses the output. */
102138fd1498Szrj if (!needed)
102238fd1498Szrj FOR_EACH_INSN_DEF (def, insn)
102338fd1498Szrj if (bitmap_bit_p (local_live, DF_REF_REGNO (def))
102438fd1498Szrj || bitmap_bit_p (au, DF_REF_REGNO (def)))
102538fd1498Szrj {
102638fd1498Szrj needed = true;
102738fd1498Szrj mark_insn (insn, true);
102838fd1498Szrj break;
102938fd1498Szrj }
103038fd1498Szrj
103138fd1498Szrj /* No matter if the instruction is needed or not, we remove
103238fd1498Szrj any regno in the defs from the live set. */
103338fd1498Szrj df_simulate_defs (insn, local_live);
103438fd1498Szrj
103538fd1498Szrj /* On the other hand, we do not allow the dead uses to set
103638fd1498Szrj anything in local_live. */
103738fd1498Szrj if (needed)
103838fd1498Szrj df_simulate_uses (insn, local_live);
103938fd1498Szrj
104038fd1498Szrj /* Insert debug temps for dead REGs used in subsequent debug
104138fd1498Szrj insns. We may have to emit a debug temp even if the insn
104238fd1498Szrj was marked, in case the debug use was after the point of
104338fd1498Szrj death. */
104438fd1498Szrj if (debug.used && !bitmap_empty_p (debug.used))
104538fd1498Szrj FOR_EACH_INSN_DEF (def, insn)
104638fd1498Szrj dead_debug_insert_temp (&debug, DF_REF_REGNO (def), insn,
104738fd1498Szrj needed && !control_flow_insn_p (insn)
104838fd1498Szrj ? DEBUG_TEMP_AFTER_WITH_REG_FORCE
104938fd1498Szrj : DEBUG_TEMP_BEFORE_WITH_VALUE);
105038fd1498Szrj }
105138fd1498Szrj
105238fd1498Szrj dead_debug_local_finish (&debug, NULL);
105338fd1498Szrj df_simulate_finalize_backwards (bb, local_live);
105438fd1498Szrj
105538fd1498Szrj block_changed = !bitmap_equal_p (local_live, DF_LR_IN (bb));
105638fd1498Szrj if (block_changed)
105738fd1498Szrj bitmap_copy (DF_LR_IN (bb), local_live);
105838fd1498Szrj
105938fd1498Szrj BITMAP_FREE (local_live);
106038fd1498Szrj return block_changed;
106138fd1498Szrj }
106238fd1498Szrj
106338fd1498Szrj
106438fd1498Szrj /* Perform fast DCE once initialization is done. If WORD_LEVEL is
106538fd1498Szrj true, use the word level dce, otherwise do it at the pseudo
106638fd1498Szrj level. */
106738fd1498Szrj
106838fd1498Szrj static void
fast_dce(bool word_level)106938fd1498Szrj fast_dce (bool word_level)
107038fd1498Szrj {
107138fd1498Szrj int *postorder = df_get_postorder (DF_BACKWARD);
107238fd1498Szrj int n_blocks = df_get_n_blocks (DF_BACKWARD);
107338fd1498Szrj /* The set of blocks that have been seen on this iteration. */
107438fd1498Szrj bitmap processed = BITMAP_ALLOC (&dce_blocks_bitmap_obstack);
107538fd1498Szrj /* The set of blocks that need to have the out vectors reset because
107638fd1498Szrj the in of one of their successors has changed. */
107738fd1498Szrj bitmap redo_out = BITMAP_ALLOC (&dce_blocks_bitmap_obstack);
107838fd1498Szrj bitmap all_blocks = BITMAP_ALLOC (&dce_blocks_bitmap_obstack);
107938fd1498Szrj bool global_changed = true;
108038fd1498Szrj
108138fd1498Szrj /* These regs are considered always live so if they end up dying
108238fd1498Szrj because of some def, we need to bring the back again. Calling
108338fd1498Szrj df_simulate_fixup_sets has the disadvantage of calling
108438fd1498Szrj bb_has_eh_pred once per insn, so we cache the information
108538fd1498Szrj here. */
108638fd1498Szrj bitmap au = &df->regular_block_artificial_uses;
108738fd1498Szrj bitmap au_eh = &df->eh_block_artificial_uses;
108838fd1498Szrj int i;
108938fd1498Szrj struct dead_debug_global global_debug;
109038fd1498Szrj
109138fd1498Szrj prescan_insns_for_dce (true);
109238fd1498Szrj
109338fd1498Szrj for (i = 0; i < n_blocks; i++)
109438fd1498Szrj bitmap_set_bit (all_blocks, postorder[i]);
109538fd1498Szrj
109638fd1498Szrj dead_debug_global_init (&global_debug, NULL);
109738fd1498Szrj
109838fd1498Szrj while (global_changed)
109938fd1498Szrj {
110038fd1498Szrj global_changed = false;
110138fd1498Szrj
110238fd1498Szrj for (i = 0; i < n_blocks; i++)
110338fd1498Szrj {
110438fd1498Szrj int index = postorder[i];
110538fd1498Szrj basic_block bb = BASIC_BLOCK_FOR_FN (cfun, index);
110638fd1498Szrj bool local_changed;
110738fd1498Szrj
110838fd1498Szrj if (index < NUM_FIXED_BLOCKS)
110938fd1498Szrj {
111038fd1498Szrj bitmap_set_bit (processed, index);
111138fd1498Szrj continue;
111238fd1498Szrj }
111338fd1498Szrj
111438fd1498Szrj if (word_level)
111538fd1498Szrj local_changed
111638fd1498Szrj = word_dce_process_block (bb, bitmap_bit_p (redo_out, index),
111738fd1498Szrj &global_debug);
111838fd1498Szrj else
111938fd1498Szrj local_changed
112038fd1498Szrj = dce_process_block (bb, bitmap_bit_p (redo_out, index),
112138fd1498Szrj bb_has_eh_pred (bb) ? au_eh : au,
112238fd1498Szrj &global_debug);
112338fd1498Szrj bitmap_set_bit (processed, index);
112438fd1498Szrj
112538fd1498Szrj if (local_changed)
112638fd1498Szrj {
112738fd1498Szrj edge e;
112838fd1498Szrj edge_iterator ei;
112938fd1498Szrj FOR_EACH_EDGE (e, ei, bb->preds)
113038fd1498Szrj if (bitmap_bit_p (processed, e->src->index))
113138fd1498Szrj /* Be tricky about when we need to iterate the
113238fd1498Szrj analysis. We only have redo the analysis if the
113338fd1498Szrj bitmaps change at the top of a block that is the
113438fd1498Szrj entry to a loop. */
113538fd1498Szrj global_changed = true;
113638fd1498Szrj else
113738fd1498Szrj bitmap_set_bit (redo_out, e->src->index);
113838fd1498Szrj }
113938fd1498Szrj }
114038fd1498Szrj
114138fd1498Szrj if (global_changed)
114238fd1498Szrj {
114338fd1498Szrj /* Turn off the RUN_DCE flag to prevent recursive calls to
114438fd1498Szrj dce. */
114538fd1498Szrj int old_flag = df_clear_flags (DF_LR_RUN_DCE);
114638fd1498Szrj
114738fd1498Szrj /* So something was deleted that requires a redo. Do it on
114838fd1498Szrj the cheap. */
114938fd1498Szrj delete_unmarked_insns ();
115038fd1498Szrj bitmap_clear (marked);
115138fd1498Szrj bitmap_clear (processed);
115238fd1498Szrj bitmap_clear (redo_out);
115338fd1498Szrj
115438fd1498Szrj /* We do not need to rescan any instructions. We only need
115538fd1498Szrj to redo the dataflow equations for the blocks that had a
115638fd1498Szrj change at the top of the block. Then we need to redo the
115738fd1498Szrj iteration. */
115838fd1498Szrj if (word_level)
115938fd1498Szrj df_analyze_problem (df_word_lr, all_blocks, postorder, n_blocks);
116038fd1498Szrj else
116138fd1498Szrj df_analyze_problem (df_lr, all_blocks, postorder, n_blocks);
116238fd1498Szrj
116338fd1498Szrj if (old_flag & DF_LR_RUN_DCE)
116438fd1498Szrj df_set_flags (DF_LR_RUN_DCE);
116538fd1498Szrj
116638fd1498Szrj prescan_insns_for_dce (true);
116738fd1498Szrj }
116838fd1498Szrj }
116938fd1498Szrj
117038fd1498Szrj dead_debug_global_finish (&global_debug, NULL);
117138fd1498Szrj
117238fd1498Szrj delete_unmarked_insns ();
117338fd1498Szrj
117438fd1498Szrj BITMAP_FREE (processed);
117538fd1498Szrj BITMAP_FREE (redo_out);
117638fd1498Szrj BITMAP_FREE (all_blocks);
117738fd1498Szrj }
117838fd1498Szrj
117938fd1498Szrj
118038fd1498Szrj /* Fast register level DCE. */
118138fd1498Szrj
118238fd1498Szrj static unsigned int
rest_of_handle_fast_dce(void)118338fd1498Szrj rest_of_handle_fast_dce (void)
118438fd1498Szrj {
118538fd1498Szrj init_dce (true);
118638fd1498Szrj fast_dce (false);
118738fd1498Szrj fini_dce (true);
118838fd1498Szrj return 0;
118938fd1498Szrj }
119038fd1498Szrj
119138fd1498Szrj
119238fd1498Szrj /* Fast byte level DCE. */
119338fd1498Szrj
119438fd1498Szrj void
run_word_dce(void)119538fd1498Szrj run_word_dce (void)
119638fd1498Szrj {
119738fd1498Szrj int old_flags;
119838fd1498Szrj
119938fd1498Szrj if (!flag_dce)
120038fd1498Szrj return;
120138fd1498Szrj
120238fd1498Szrj timevar_push (TV_DCE);
120338fd1498Szrj old_flags = df_clear_flags (DF_DEFER_INSN_RESCAN + DF_NO_INSN_RESCAN);
120438fd1498Szrj df_word_lr_add_problem ();
120538fd1498Szrj init_dce (true);
120638fd1498Szrj fast_dce (true);
120738fd1498Szrj fini_dce (true);
120838fd1498Szrj df_set_flags (old_flags);
120938fd1498Szrj timevar_pop (TV_DCE);
121038fd1498Szrj }
121138fd1498Szrj
121238fd1498Szrj
121338fd1498Szrj /* This is an internal call that is used by the df live register
121438fd1498Szrj problem to run fast dce as a side effect of creating the live
121538fd1498Szrj information. The stack is organized so that the lr problem is run,
121638fd1498Szrj this pass is run, which updates the live info and the df scanning
121738fd1498Szrj info, and then returns to allow the rest of the problems to be run.
121838fd1498Szrj
121938fd1498Szrj This can be called by elsewhere but it will not update the bit
122038fd1498Szrj vectors for any other problems than LR. */
122138fd1498Szrj
122238fd1498Szrj void
run_fast_df_dce(void)122338fd1498Szrj run_fast_df_dce (void)
122438fd1498Szrj {
122538fd1498Szrj if (flag_dce)
122638fd1498Szrj {
122738fd1498Szrj /* If dce is able to delete something, it has to happen
122838fd1498Szrj immediately. Otherwise there will be problems handling the
122938fd1498Szrj eq_notes. */
123038fd1498Szrj int old_flags =
123138fd1498Szrj df_clear_flags (DF_DEFER_INSN_RESCAN + DF_NO_INSN_RESCAN);
123238fd1498Szrj
123338fd1498Szrj df_in_progress = true;
123438fd1498Szrj rest_of_handle_fast_dce ();
123538fd1498Szrj df_in_progress = false;
123638fd1498Szrj
123738fd1498Szrj df_set_flags (old_flags);
123838fd1498Szrj }
123938fd1498Szrj }
124038fd1498Szrj
124138fd1498Szrj
124238fd1498Szrj /* Run a fast DCE pass. */
124338fd1498Szrj
124438fd1498Szrj void
run_fast_dce(void)124538fd1498Szrj run_fast_dce (void)
124638fd1498Szrj {
124738fd1498Szrj if (flag_dce)
124838fd1498Szrj rest_of_handle_fast_dce ();
124938fd1498Szrj }
125038fd1498Szrj
125138fd1498Szrj
125238fd1498Szrj namespace {
125338fd1498Szrj
125438fd1498Szrj const pass_data pass_data_fast_rtl_dce =
125538fd1498Szrj {
125638fd1498Szrj RTL_PASS, /* type */
125738fd1498Szrj "rtl_dce", /* name */
125838fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
125938fd1498Szrj TV_DCE, /* tv_id */
126038fd1498Szrj 0, /* properties_required */
126138fd1498Szrj 0, /* properties_provided */
126238fd1498Szrj 0, /* properties_destroyed */
126338fd1498Szrj 0, /* todo_flags_start */
126438fd1498Szrj TODO_df_finish, /* todo_flags_finish */
126538fd1498Szrj };
126638fd1498Szrj
126738fd1498Szrj class pass_fast_rtl_dce : public rtl_opt_pass
126838fd1498Szrj {
126938fd1498Szrj public:
pass_fast_rtl_dce(gcc::context * ctxt)127038fd1498Szrj pass_fast_rtl_dce (gcc::context *ctxt)
127138fd1498Szrj : rtl_opt_pass (pass_data_fast_rtl_dce, ctxt)
127238fd1498Szrj {}
127338fd1498Szrj
127438fd1498Szrj /* opt_pass methods: */
gate(function *)127538fd1498Szrj virtual bool gate (function *)
127638fd1498Szrj {
127738fd1498Szrj return optimize > 0 && flag_dce && dbg_cnt (dce_fast);
127838fd1498Szrj }
127938fd1498Szrj
execute(function *)128038fd1498Szrj virtual unsigned int execute (function *)
128138fd1498Szrj {
128238fd1498Szrj return rest_of_handle_fast_dce ();
128338fd1498Szrj }
128438fd1498Szrj
128538fd1498Szrj }; // class pass_fast_rtl_dce
128638fd1498Szrj
128738fd1498Szrj } // anon namespace
128838fd1498Szrj
128938fd1498Szrj rtl_opt_pass *
make_pass_fast_rtl_dce(gcc::context * ctxt)129038fd1498Szrj make_pass_fast_rtl_dce (gcc::context *ctxt)
129138fd1498Szrj {
129238fd1498Szrj return new pass_fast_rtl_dce (ctxt);
129338fd1498Szrj }
1294