xref: /dflybsd-src/contrib/gcc-8.0/gcc/dce.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
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