xref: /dflybsd-src/contrib/gcc-8.0/gcc/dce.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
1*38fd1498Szrj /* RTL dead code elimination.
2*38fd1498Szrj    Copyright (C) 2005-2018 Free Software Foundation, Inc.
3*38fd1498Szrj 
4*38fd1498Szrj This file is part of GCC.
5*38fd1498Szrj 
6*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
7*38fd1498Szrj the terms of the GNU General Public License as published by the Free
8*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
9*38fd1498Szrj version.
10*38fd1498Szrj 
11*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14*38fd1498Szrj for more details.
15*38fd1498Szrj 
16*38fd1498Szrj You should have received a copy of the GNU General Public License
17*38fd1498Szrj along with GCC; see the file COPYING3.  If not see
18*38fd1498Szrj <http://www.gnu.org/licenses/>.  */
19*38fd1498Szrj 
20*38fd1498Szrj #include "config.h"
21*38fd1498Szrj #include "system.h"
22*38fd1498Szrj #include "coretypes.h"
23*38fd1498Szrj #include "backend.h"
24*38fd1498Szrj #include "rtl.h"
25*38fd1498Szrj #include "tree.h"
26*38fd1498Szrj #include "predict.h"
27*38fd1498Szrj #include "df.h"
28*38fd1498Szrj #include "memmodel.h"
29*38fd1498Szrj #include "tm_p.h"
30*38fd1498Szrj #include "emit-rtl.h"  /* FIXME: Can go away once crtl is moved to rtl.h.  */
31*38fd1498Szrj #include "cfgrtl.h"
32*38fd1498Szrj #include "cfgbuild.h"
33*38fd1498Szrj #include "cfgcleanup.h"
34*38fd1498Szrj #include "dce.h"
35*38fd1498Szrj #include "valtrack.h"
36*38fd1498Szrj #include "tree-pass.h"
37*38fd1498Szrj #include "dbgcnt.h"
38*38fd1498Szrj 
39*38fd1498Szrj 
40*38fd1498Szrj /* -------------------------------------------------------------------------
41*38fd1498Szrj    Core mark/delete routines
42*38fd1498Szrj    ------------------------------------------------------------------------- */
43*38fd1498Szrj 
44*38fd1498Szrj /* True if we are invoked while the df engine is running; in this case,
45*38fd1498Szrj    we don't want to reenter it.  */
46*38fd1498Szrj static bool df_in_progress = false;
47*38fd1498Szrj 
48*38fd1498Szrj /* True if we are allowed to alter the CFG in this pass.  */
49*38fd1498Szrj static bool can_alter_cfg = false;
50*38fd1498Szrj 
51*38fd1498Szrj /* Instructions that have been marked but whose dependencies have not
52*38fd1498Szrj    yet been processed.  */
53*38fd1498Szrj static vec<rtx_insn *> worklist;
54*38fd1498Szrj 
55*38fd1498Szrj /* Bitmap of instructions marked as needed indexed by INSN_UID.  */
56*38fd1498Szrj static sbitmap marked;
57*38fd1498Szrj 
58*38fd1498Szrj /* Bitmap obstacks used for block processing by the fast algorithm.  */
59*38fd1498Szrj static bitmap_obstack dce_blocks_bitmap_obstack;
60*38fd1498Szrj static bitmap_obstack dce_tmp_bitmap_obstack;
61*38fd1498Szrj 
62*38fd1498Szrj static bool find_call_stack_args (rtx_call_insn *, bool, bool, bitmap);
63*38fd1498Szrj 
64*38fd1498Szrj /* A subroutine for which BODY is part of the instruction being tested;
65*38fd1498Szrj    either the top-level pattern, or an element of a PARALLEL.  The
66*38fd1498Szrj    instruction is known not to be a bare USE or CLOBBER.  */
67*38fd1498Szrj 
68*38fd1498Szrj static bool
69*38fd1498Szrj deletable_insn_p_1 (rtx body)
70*38fd1498Szrj {
71*38fd1498Szrj   switch (GET_CODE (body))
72*38fd1498Szrj     {
73*38fd1498Szrj     case PREFETCH:
74*38fd1498Szrj     case TRAP_IF:
75*38fd1498Szrj       /* The UNSPEC case was added here because the ia-64 claims that
76*38fd1498Szrj 	 USEs do not work after reload and generates UNSPECS rather
77*38fd1498Szrj 	 than USEs.  Since dce is run after reload we need to avoid
78*38fd1498Szrj 	 deleting these even if they are dead.  If it turns out that
79*38fd1498Szrj 	 USEs really do work after reload, the ia-64 should be
80*38fd1498Szrj 	 changed, and the UNSPEC case can be removed.  */
81*38fd1498Szrj     case UNSPEC:
82*38fd1498Szrj       return false;
83*38fd1498Szrj 
84*38fd1498Szrj     default:
85*38fd1498Szrj       return !volatile_refs_p (body);
86*38fd1498Szrj     }
87*38fd1498Szrj }
88*38fd1498Szrj 
89*38fd1498Szrj 
90*38fd1498Szrj /* Return true if INSN is a normal instruction that can be deleted by
91*38fd1498Szrj    the DCE pass.  */
92*38fd1498Szrj 
93*38fd1498Szrj static bool
94*38fd1498Szrj deletable_insn_p (rtx_insn *insn, bool fast, bitmap arg_stores)
95*38fd1498Szrj {
96*38fd1498Szrj   rtx body, x;
97*38fd1498Szrj   int i;
98*38fd1498Szrj   df_ref def;
99*38fd1498Szrj 
100*38fd1498Szrj   if (CALL_P (insn)
101*38fd1498Szrj       /* We cannot delete calls inside of the recursive dce because
102*38fd1498Szrj 	 this may cause basic blocks to be deleted and this messes up
103*38fd1498Szrj 	 the rest of the stack of optimization passes.  */
104*38fd1498Szrj       && (!df_in_progress)
105*38fd1498Szrj       /* We cannot delete pure or const sibling calls because it is
106*38fd1498Szrj 	 hard to see the result.  */
107*38fd1498Szrj       && (!SIBLING_CALL_P (insn))
108*38fd1498Szrj       /* We can delete dead const or pure calls as long as they do not
109*38fd1498Szrj          infinite loop.  */
110*38fd1498Szrj       && (RTL_CONST_OR_PURE_CALL_P (insn)
111*38fd1498Szrj 	  && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)))
112*38fd1498Szrj     return find_call_stack_args (as_a <rtx_call_insn *> (insn), false,
113*38fd1498Szrj 				 fast, arg_stores);
114*38fd1498Szrj 
115*38fd1498Szrj   /* Don't delete jumps, notes and the like.  */
116*38fd1498Szrj   if (!NONJUMP_INSN_P (insn))
117*38fd1498Szrj     return false;
118*38fd1498Szrj 
119*38fd1498Szrj   /* Don't delete insns that may throw if we cannot do so.  */
120*38fd1498Szrj   if (!(cfun->can_delete_dead_exceptions && can_alter_cfg)
121*38fd1498Szrj       && !insn_nothrow_p (insn))
122*38fd1498Szrj     return false;
123*38fd1498Szrj 
124*38fd1498Szrj   /* If INSN sets a global_reg, leave it untouched.  */
125*38fd1498Szrj   FOR_EACH_INSN_DEF (def, insn)
126*38fd1498Szrj     if (HARD_REGISTER_NUM_P (DF_REF_REGNO (def))
127*38fd1498Szrj 	&& global_regs[DF_REF_REGNO (def)])
128*38fd1498Szrj       return false;
129*38fd1498Szrj     /* Initialization of pseudo PIC register should never be removed.  */
130*38fd1498Szrj     else if (DF_REF_REG (def) == pic_offset_table_rtx
131*38fd1498Szrj 	     && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
132*38fd1498Szrj       return false;
133*38fd1498Szrj 
134*38fd1498Szrj   /* Callee-save restores are needed.  */
135*38fd1498Szrj   if (RTX_FRAME_RELATED_P (insn)
136*38fd1498Szrj       && crtl->shrink_wrapped_separate
137*38fd1498Szrj       && find_reg_note (insn, REG_CFA_RESTORE, NULL))
138*38fd1498Szrj     return false;
139*38fd1498Szrj 
140*38fd1498Szrj   body = PATTERN (insn);
141*38fd1498Szrj   switch (GET_CODE (body))
142*38fd1498Szrj     {
143*38fd1498Szrj     case USE:
144*38fd1498Szrj     case VAR_LOCATION:
145*38fd1498Szrj       return false;
146*38fd1498Szrj 
147*38fd1498Szrj     case CLOBBER:
148*38fd1498Szrj       if (fast)
149*38fd1498Szrj 	{
150*38fd1498Szrj 	  /* A CLOBBER of a dead pseudo register serves no purpose.
151*38fd1498Szrj 	     That is not necessarily true for hard registers until
152*38fd1498Szrj 	     after reload.  */
153*38fd1498Szrj 	  x = XEXP (body, 0);
154*38fd1498Szrj 	  return REG_P (x) && (!HARD_REGISTER_P (x) || reload_completed);
155*38fd1498Szrj 	}
156*38fd1498Szrj       else
157*38fd1498Szrj 	/* Because of the way that use-def chains are built, it is not
158*38fd1498Szrj 	   possible to tell if the clobber is dead because it can
159*38fd1498Szrj 	   never be the target of a use-def chain.  */
160*38fd1498Szrj 	return false;
161*38fd1498Szrj 
162*38fd1498Szrj     case PARALLEL:
163*38fd1498Szrj       for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
164*38fd1498Szrj 	if (!deletable_insn_p_1 (XVECEXP (body, 0, i)))
165*38fd1498Szrj 	  return false;
166*38fd1498Szrj       return true;
167*38fd1498Szrj 
168*38fd1498Szrj     default:
169*38fd1498Szrj       return deletable_insn_p_1 (body);
170*38fd1498Szrj     }
171*38fd1498Szrj }
172*38fd1498Szrj 
173*38fd1498Szrj 
174*38fd1498Szrj /* Return true if INSN has been marked as needed.  */
175*38fd1498Szrj 
176*38fd1498Szrj static inline int
177*38fd1498Szrj marked_insn_p (rtx_insn *insn)
178*38fd1498Szrj {
179*38fd1498Szrj   /* Artificial defs are always needed and they do not have an insn.
180*38fd1498Szrj      We should never see them here.  */
181*38fd1498Szrj   gcc_assert (insn);
182*38fd1498Szrj   return bitmap_bit_p (marked, INSN_UID (insn));
183*38fd1498Szrj }
184*38fd1498Szrj 
185*38fd1498Szrj 
186*38fd1498Szrj /* If INSN has not yet been marked as needed, mark it now, and add it to
187*38fd1498Szrj    the worklist.  */
188*38fd1498Szrj 
189*38fd1498Szrj static void
190*38fd1498Szrj mark_insn (rtx_insn *insn, bool fast)
191*38fd1498Szrj {
192*38fd1498Szrj   if (!marked_insn_p (insn))
193*38fd1498Szrj     {
194*38fd1498Szrj       if (!fast)
195*38fd1498Szrj 	worklist.safe_push (insn);
196*38fd1498Szrj       bitmap_set_bit (marked, INSN_UID (insn));
197*38fd1498Szrj       if (dump_file)
198*38fd1498Szrj 	fprintf (dump_file, "  Adding insn %d to worklist\n", INSN_UID (insn));
199*38fd1498Szrj       if (CALL_P (insn)
200*38fd1498Szrj 	  && !df_in_progress
201*38fd1498Szrj 	  && !SIBLING_CALL_P (insn)
202*38fd1498Szrj 	  && (RTL_CONST_OR_PURE_CALL_P (insn)
203*38fd1498Szrj 	      && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)))
204*38fd1498Szrj 	find_call_stack_args (as_a <rtx_call_insn *> (insn), true, fast, NULL);
205*38fd1498Szrj     }
206*38fd1498Szrj }
207*38fd1498Szrj 
208*38fd1498Szrj 
209*38fd1498Szrj /* A note_stores callback used by mark_nonreg_stores.  DATA is the
210*38fd1498Szrj    instruction containing DEST.  */
211*38fd1498Szrj 
212*38fd1498Szrj static void
213*38fd1498Szrj mark_nonreg_stores_1 (rtx dest, const_rtx pattern, void *data)
214*38fd1498Szrj {
215*38fd1498Szrj   if (GET_CODE (pattern) != CLOBBER && !REG_P (dest))
216*38fd1498Szrj     mark_insn ((rtx_insn *) data, true);
217*38fd1498Szrj }
218*38fd1498Szrj 
219*38fd1498Szrj 
220*38fd1498Szrj /* A note_stores callback used by mark_nonreg_stores.  DATA is the
221*38fd1498Szrj    instruction containing DEST.  */
222*38fd1498Szrj 
223*38fd1498Szrj static void
224*38fd1498Szrj mark_nonreg_stores_2 (rtx dest, const_rtx pattern, void *data)
225*38fd1498Szrj {
226*38fd1498Szrj   if (GET_CODE (pattern) != CLOBBER && !REG_P (dest))
227*38fd1498Szrj     mark_insn ((rtx_insn *) data, false);
228*38fd1498Szrj }
229*38fd1498Szrj 
230*38fd1498Szrj 
231*38fd1498Szrj /* Mark INSN if BODY stores to a non-register destination.  */
232*38fd1498Szrj 
233*38fd1498Szrj static void
234*38fd1498Szrj mark_nonreg_stores (rtx body, rtx_insn *insn, bool fast)
235*38fd1498Szrj {
236*38fd1498Szrj   if (fast)
237*38fd1498Szrj     note_stores (body, mark_nonreg_stores_1, insn);
238*38fd1498Szrj   else
239*38fd1498Szrj     note_stores (body, mark_nonreg_stores_2, insn);
240*38fd1498Szrj }
241*38fd1498Szrj 
242*38fd1498Szrj 
243*38fd1498Szrj /* Return true if a store to SIZE bytes, starting OFF bytes from stack pointer,
244*38fd1498Szrj    is a call argument store, and clear corresponding bits from SP_BYTES
245*38fd1498Szrj    bitmap if it is.  */
246*38fd1498Szrj 
247*38fd1498Szrj static bool
248*38fd1498Szrj check_argument_store (HOST_WIDE_INT size, HOST_WIDE_INT off,
249*38fd1498Szrj 		      HOST_WIDE_INT min_sp_off, HOST_WIDE_INT max_sp_off,
250*38fd1498Szrj 		      bitmap sp_bytes)
251*38fd1498Szrj {
252*38fd1498Szrj   HOST_WIDE_INT byte;
253*38fd1498Szrj   for (byte = off; byte < off + size; byte++)
254*38fd1498Szrj     {
255*38fd1498Szrj       if (byte < min_sp_off
256*38fd1498Szrj 	  || byte >= max_sp_off
257*38fd1498Szrj 	  || !bitmap_clear_bit (sp_bytes, byte - min_sp_off))
258*38fd1498Szrj 	return false;
259*38fd1498Szrj     }
260*38fd1498Szrj   return true;
261*38fd1498Szrj }
262*38fd1498Szrj 
263*38fd1498Szrj 
264*38fd1498Szrj /* Try to find all stack stores of CALL_INSN arguments if
265*38fd1498Szrj    ACCUMULATE_OUTGOING_ARGS.  If all stack stores have been found
266*38fd1498Szrj    and it is therefore safe to eliminate the call, return true,
267*38fd1498Szrj    otherwise return false.  This function should be first called
268*38fd1498Szrj    with DO_MARK false, and only when the CALL_INSN is actually
269*38fd1498Szrj    going to be marked called again with DO_MARK true.  */
270*38fd1498Szrj 
271*38fd1498Szrj static bool
272*38fd1498Szrj find_call_stack_args (rtx_call_insn *call_insn, bool do_mark, bool fast,
273*38fd1498Szrj 		      bitmap arg_stores)
274*38fd1498Szrj {
275*38fd1498Szrj   rtx p;
276*38fd1498Szrj   rtx_insn *insn, *prev_insn;
277*38fd1498Szrj   bool ret;
278*38fd1498Szrj   HOST_WIDE_INT min_sp_off, max_sp_off;
279*38fd1498Szrj   bitmap sp_bytes;
280*38fd1498Szrj 
281*38fd1498Szrj   gcc_assert (CALL_P (call_insn));
282*38fd1498Szrj   if (!ACCUMULATE_OUTGOING_ARGS)
283*38fd1498Szrj     return true;
284*38fd1498Szrj 
285*38fd1498Szrj   if (!do_mark)
286*38fd1498Szrj     {
287*38fd1498Szrj       gcc_assert (arg_stores);
288*38fd1498Szrj       bitmap_clear (arg_stores);
289*38fd1498Szrj     }
290*38fd1498Szrj 
291*38fd1498Szrj   min_sp_off = INTTYPE_MAXIMUM (HOST_WIDE_INT);
292*38fd1498Szrj   max_sp_off = 0;
293*38fd1498Szrj 
294*38fd1498Szrj   /* First determine the minimum and maximum offset from sp for
295*38fd1498Szrj      stored arguments.  */
296*38fd1498Szrj   for (p = CALL_INSN_FUNCTION_USAGE (call_insn); p; p = XEXP (p, 1))
297*38fd1498Szrj     if (GET_CODE (XEXP (p, 0)) == USE
298*38fd1498Szrj 	&& MEM_P (XEXP (XEXP (p, 0), 0)))
299*38fd1498Szrj       {
300*38fd1498Szrj 	rtx mem = XEXP (XEXP (p, 0), 0), addr;
301*38fd1498Szrj 	HOST_WIDE_INT off = 0, size;
302*38fd1498Szrj 	if (!MEM_SIZE_KNOWN_P (mem) || !MEM_SIZE (mem).is_constant (&size))
303*38fd1498Szrj 	  return false;
304*38fd1498Szrj 	addr = XEXP (mem, 0);
305*38fd1498Szrj 	if (GET_CODE (addr) == PLUS
306*38fd1498Szrj 	    && REG_P (XEXP (addr, 0))
307*38fd1498Szrj 	    && CONST_INT_P (XEXP (addr, 1)))
308*38fd1498Szrj 	  {
309*38fd1498Szrj 	    off = INTVAL (XEXP (addr, 1));
310*38fd1498Szrj 	    addr = XEXP (addr, 0);
311*38fd1498Szrj 	  }
312*38fd1498Szrj 	if (addr != stack_pointer_rtx)
313*38fd1498Szrj 	  {
314*38fd1498Szrj 	    if (!REG_P (addr))
315*38fd1498Szrj 	      return false;
316*38fd1498Szrj 	    /* If not fast, use chains to see if addr wasn't set to
317*38fd1498Szrj 	       sp + offset.  */
318*38fd1498Szrj 	    if (!fast)
319*38fd1498Szrj 	      {
320*38fd1498Szrj 		df_ref use;
321*38fd1498Szrj 		struct df_link *defs;
322*38fd1498Szrj 		rtx set;
323*38fd1498Szrj 
324*38fd1498Szrj 		FOR_EACH_INSN_USE (use, call_insn)
325*38fd1498Szrj 		  if (rtx_equal_p (addr, DF_REF_REG (use)))
326*38fd1498Szrj 		    break;
327*38fd1498Szrj 
328*38fd1498Szrj 		if (use == NULL)
329*38fd1498Szrj 		  return false;
330*38fd1498Szrj 
331*38fd1498Szrj 		for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
332*38fd1498Szrj 		  if (! DF_REF_IS_ARTIFICIAL (defs->ref))
333*38fd1498Szrj 		    break;
334*38fd1498Szrj 
335*38fd1498Szrj 		if (defs == NULL)
336*38fd1498Szrj 		  return false;
337*38fd1498Szrj 
338*38fd1498Szrj 		set = single_set (DF_REF_INSN (defs->ref));
339*38fd1498Szrj 		if (!set)
340*38fd1498Szrj 		  return false;
341*38fd1498Szrj 
342*38fd1498Szrj 		if (GET_CODE (SET_SRC (set)) != PLUS
343*38fd1498Szrj 		    || XEXP (SET_SRC (set), 0) != stack_pointer_rtx
344*38fd1498Szrj 		    || !CONST_INT_P (XEXP (SET_SRC (set), 1)))
345*38fd1498Szrj 		  return false;
346*38fd1498Szrj 
347*38fd1498Szrj 		off += INTVAL (XEXP (SET_SRC (set), 1));
348*38fd1498Szrj 	      }
349*38fd1498Szrj 	    else
350*38fd1498Szrj 	      return false;
351*38fd1498Szrj 	  }
352*38fd1498Szrj 	min_sp_off = MIN (min_sp_off, off);
353*38fd1498Szrj 	max_sp_off = MAX (max_sp_off, off + size);
354*38fd1498Szrj       }
355*38fd1498Szrj 
356*38fd1498Szrj   if (min_sp_off >= max_sp_off)
357*38fd1498Szrj     return true;
358*38fd1498Szrj   sp_bytes = BITMAP_ALLOC (NULL);
359*38fd1498Szrj 
360*38fd1498Szrj   /* Set bits in SP_BYTES bitmap for bytes relative to sp + min_sp_off
361*38fd1498Szrj      which contain arguments.  Checking has been done in the previous
362*38fd1498Szrj      loop.  */
363*38fd1498Szrj   for (p = CALL_INSN_FUNCTION_USAGE (call_insn); p; p = XEXP (p, 1))
364*38fd1498Szrj     if (GET_CODE (XEXP (p, 0)) == USE
365*38fd1498Szrj 	&& MEM_P (XEXP (XEXP (p, 0), 0)))
366*38fd1498Szrj       {
367*38fd1498Szrj 	rtx mem = XEXP (XEXP (p, 0), 0), addr;
368*38fd1498Szrj 	HOST_WIDE_INT off = 0, byte, size;
369*38fd1498Szrj 	/* Checked in the previous iteration.  */
370*38fd1498Szrj 	size = MEM_SIZE (mem).to_constant ();
371*38fd1498Szrj 	addr = XEXP (mem, 0);
372*38fd1498Szrj 	if (GET_CODE (addr) == PLUS
373*38fd1498Szrj 	    && REG_P (XEXP (addr, 0))
374*38fd1498Szrj 	    && CONST_INT_P (XEXP (addr, 1)))
375*38fd1498Szrj 	  {
376*38fd1498Szrj 	    off = INTVAL (XEXP (addr, 1));
377*38fd1498Szrj 	    addr = XEXP (addr, 0);
378*38fd1498Szrj 	  }
379*38fd1498Szrj 	if (addr != stack_pointer_rtx)
380*38fd1498Szrj 	  {
381*38fd1498Szrj 	    df_ref use;
382*38fd1498Szrj 	    struct df_link *defs;
383*38fd1498Szrj 	    rtx set;
384*38fd1498Szrj 
385*38fd1498Szrj 	    FOR_EACH_INSN_USE (use, call_insn)
386*38fd1498Szrj 	      if (rtx_equal_p (addr, DF_REF_REG (use)))
387*38fd1498Szrj 		break;
388*38fd1498Szrj 
389*38fd1498Szrj 	    for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
390*38fd1498Szrj 	      if (! DF_REF_IS_ARTIFICIAL (defs->ref))
391*38fd1498Szrj 		break;
392*38fd1498Szrj 
393*38fd1498Szrj 	    set = single_set (DF_REF_INSN (defs->ref));
394*38fd1498Szrj 	    off += INTVAL (XEXP (SET_SRC (set), 1));
395*38fd1498Szrj 	  }
396*38fd1498Szrj 	for (byte = off; byte < off + size; byte++)
397*38fd1498Szrj 	  {
398*38fd1498Szrj 	    if (!bitmap_set_bit (sp_bytes, byte - min_sp_off))
399*38fd1498Szrj 	      gcc_unreachable ();
400*38fd1498Szrj 	  }
401*38fd1498Szrj       }
402*38fd1498Szrj 
403*38fd1498Szrj   /* Walk backwards, looking for argument stores.  The search stops
404*38fd1498Szrj      when seeing another call, sp adjustment or memory store other than
405*38fd1498Szrj      argument store.  */
406*38fd1498Szrj   ret = false;
407*38fd1498Szrj   for (insn = PREV_INSN (call_insn); insn; insn = prev_insn)
408*38fd1498Szrj     {
409*38fd1498Szrj       rtx set, mem, addr;
410*38fd1498Szrj       HOST_WIDE_INT off;
411*38fd1498Szrj 
412*38fd1498Szrj       if (insn == BB_HEAD (BLOCK_FOR_INSN (call_insn)))
413*38fd1498Szrj 	prev_insn = NULL;
414*38fd1498Szrj       else
415*38fd1498Szrj 	prev_insn = PREV_INSN (insn);
416*38fd1498Szrj 
417*38fd1498Szrj       if (CALL_P (insn))
418*38fd1498Szrj 	break;
419*38fd1498Szrj 
420*38fd1498Szrj       if (!NONDEBUG_INSN_P (insn))
421*38fd1498Szrj 	continue;
422*38fd1498Szrj 
423*38fd1498Szrj       set = single_set (insn);
424*38fd1498Szrj       if (!set || SET_DEST (set) == stack_pointer_rtx)
425*38fd1498Szrj 	break;
426*38fd1498Szrj 
427*38fd1498Szrj       if (!MEM_P (SET_DEST (set)))
428*38fd1498Szrj 	continue;
429*38fd1498Szrj 
430*38fd1498Szrj       mem = SET_DEST (set);
431*38fd1498Szrj       addr = XEXP (mem, 0);
432*38fd1498Szrj       off = 0;
433*38fd1498Szrj       if (GET_CODE (addr) == PLUS
434*38fd1498Szrj 	  && REG_P (XEXP (addr, 0))
435*38fd1498Szrj 	  && CONST_INT_P (XEXP (addr, 1)))
436*38fd1498Szrj 	{
437*38fd1498Szrj 	  off = INTVAL (XEXP (addr, 1));
438*38fd1498Szrj 	  addr = XEXP (addr, 0);
439*38fd1498Szrj 	}
440*38fd1498Szrj       if (addr != stack_pointer_rtx)
441*38fd1498Szrj 	{
442*38fd1498Szrj 	  if (!REG_P (addr))
443*38fd1498Szrj 	    break;
444*38fd1498Szrj 	  if (!fast)
445*38fd1498Szrj 	    {
446*38fd1498Szrj 	      df_ref use;
447*38fd1498Szrj 	      struct df_link *defs;
448*38fd1498Szrj 	      rtx set;
449*38fd1498Szrj 
450*38fd1498Szrj 	      FOR_EACH_INSN_USE (use, insn)
451*38fd1498Szrj 		if (rtx_equal_p (addr, DF_REF_REG (use)))
452*38fd1498Szrj 		  break;
453*38fd1498Szrj 
454*38fd1498Szrj 	      if (use == NULL)
455*38fd1498Szrj 		break;
456*38fd1498Szrj 
457*38fd1498Szrj 	      for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
458*38fd1498Szrj 		if (! DF_REF_IS_ARTIFICIAL (defs->ref))
459*38fd1498Szrj 		  break;
460*38fd1498Szrj 
461*38fd1498Szrj 	      if (defs == NULL)
462*38fd1498Szrj 		break;
463*38fd1498Szrj 
464*38fd1498Szrj 	      set = single_set (DF_REF_INSN (defs->ref));
465*38fd1498Szrj 	      if (!set)
466*38fd1498Szrj 		break;
467*38fd1498Szrj 
468*38fd1498Szrj 	      if (GET_CODE (SET_SRC (set)) != PLUS
469*38fd1498Szrj 		  || XEXP (SET_SRC (set), 0) != stack_pointer_rtx
470*38fd1498Szrj 		  || !CONST_INT_P (XEXP (SET_SRC (set), 1)))
471*38fd1498Szrj 		break;
472*38fd1498Szrj 
473*38fd1498Szrj 	      off += INTVAL (XEXP (SET_SRC (set), 1));
474*38fd1498Szrj 	    }
475*38fd1498Szrj 	  else
476*38fd1498Szrj 	    break;
477*38fd1498Szrj 	}
478*38fd1498Szrj 
479*38fd1498Szrj       HOST_WIDE_INT size;
480*38fd1498Szrj       if (!MEM_SIZE_KNOWN_P (mem)
481*38fd1498Szrj 	  || !MEM_SIZE (mem).is_constant (&size)
482*38fd1498Szrj 	  || !check_argument_store (size, off, min_sp_off,
483*38fd1498Szrj 				    max_sp_off, sp_bytes))
484*38fd1498Szrj 	break;
485*38fd1498Szrj 
486*38fd1498Szrj       if (!deletable_insn_p (insn, fast, NULL))
487*38fd1498Szrj 	break;
488*38fd1498Szrj 
489*38fd1498Szrj       if (do_mark)
490*38fd1498Szrj 	mark_insn (insn, fast);
491*38fd1498Szrj       else
492*38fd1498Szrj 	bitmap_set_bit (arg_stores, INSN_UID (insn));
493*38fd1498Szrj 
494*38fd1498Szrj       if (bitmap_empty_p (sp_bytes))
495*38fd1498Szrj 	{
496*38fd1498Szrj 	  ret = true;
497*38fd1498Szrj 	  break;
498*38fd1498Szrj 	}
499*38fd1498Szrj     }
500*38fd1498Szrj 
501*38fd1498Szrj   BITMAP_FREE (sp_bytes);
502*38fd1498Szrj   if (!ret && arg_stores)
503*38fd1498Szrj     bitmap_clear (arg_stores);
504*38fd1498Szrj 
505*38fd1498Szrj   return ret;
506*38fd1498Szrj }
507*38fd1498Szrj 
508*38fd1498Szrj 
509*38fd1498Szrj /* Remove all REG_EQUAL and REG_EQUIV notes referring to the registers INSN
510*38fd1498Szrj    writes to.  */
511*38fd1498Szrj 
512*38fd1498Szrj static void
513*38fd1498Szrj remove_reg_equal_equiv_notes_for_defs (rtx_insn *insn)
514*38fd1498Szrj {
515*38fd1498Szrj   df_ref def;
516*38fd1498Szrj 
517*38fd1498Szrj   FOR_EACH_INSN_DEF (def, insn)
518*38fd1498Szrj     remove_reg_equal_equiv_notes_for_regno (DF_REF_REGNO (def));
519*38fd1498Szrj }
520*38fd1498Szrj 
521*38fd1498Szrj /* Scan all BBs for debug insns and reset those that reference values
522*38fd1498Szrj    defined in unmarked insns.  */
523*38fd1498Szrj 
524*38fd1498Szrj static void
525*38fd1498Szrj reset_unmarked_insns_debug_uses (void)
526*38fd1498Szrj {
527*38fd1498Szrj   basic_block bb;
528*38fd1498Szrj   rtx_insn *insn, *next;
529*38fd1498Szrj 
530*38fd1498Szrj   FOR_EACH_BB_REVERSE_FN (bb, cfun)
531*38fd1498Szrj     FOR_BB_INSNS_REVERSE_SAFE (bb, insn, next)
532*38fd1498Szrj       if (DEBUG_INSN_P (insn))
533*38fd1498Szrj 	{
534*38fd1498Szrj 	  df_ref use;
535*38fd1498Szrj 
536*38fd1498Szrj 	  FOR_EACH_INSN_USE (use, insn)
537*38fd1498Szrj 	    {
538*38fd1498Szrj 	      struct df_link *defs;
539*38fd1498Szrj 	      for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
540*38fd1498Szrj 		{
541*38fd1498Szrj 		  rtx_insn *ref_insn;
542*38fd1498Szrj 		  if (DF_REF_IS_ARTIFICIAL (defs->ref))
543*38fd1498Szrj 		    continue;
544*38fd1498Szrj 		  ref_insn = DF_REF_INSN (defs->ref);
545*38fd1498Szrj 		  if (!marked_insn_p (ref_insn))
546*38fd1498Szrj 		    break;
547*38fd1498Szrj 		}
548*38fd1498Szrj 	      if (!defs)
549*38fd1498Szrj 		continue;
550*38fd1498Szrj 	      /* ??? FIXME could we propagate the values assigned to
551*38fd1498Szrj 		 each of the DEFs?  */
552*38fd1498Szrj 	      INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
553*38fd1498Szrj 	      df_insn_rescan_debug_internal (insn);
554*38fd1498Szrj 	      break;
555*38fd1498Szrj 	    }
556*38fd1498Szrj 	}
557*38fd1498Szrj }
558*38fd1498Szrj 
559*38fd1498Szrj /* Delete every instruction that hasn't been marked.  */
560*38fd1498Szrj 
561*38fd1498Szrj static void
562*38fd1498Szrj delete_unmarked_insns (void)
563*38fd1498Szrj {
564*38fd1498Szrj   basic_block bb;
565*38fd1498Szrj   rtx_insn *insn, *next;
566*38fd1498Szrj   bool must_clean = false;
567*38fd1498Szrj 
568*38fd1498Szrj   FOR_EACH_BB_REVERSE_FN (bb, cfun)
569*38fd1498Szrj     FOR_BB_INSNS_REVERSE_SAFE (bb, insn, next)
570*38fd1498Szrj       if (NONDEBUG_INSN_P (insn))
571*38fd1498Szrj 	{
572*38fd1498Szrj 	  rtx turn_into_use = NULL_RTX;
573*38fd1498Szrj 
574*38fd1498Szrj 	  /* Always delete no-op moves.  */
575*38fd1498Szrj 	  if (noop_move_p (insn))
576*38fd1498Szrj 	    {
577*38fd1498Szrj 	      if (RTX_FRAME_RELATED_P (insn))
578*38fd1498Szrj 		turn_into_use
579*38fd1498Szrj 		  = find_reg_note (insn, REG_CFA_RESTORE, NULL);
580*38fd1498Szrj 	      if (turn_into_use && REG_P (XEXP (turn_into_use, 0)))
581*38fd1498Szrj 		turn_into_use = XEXP (turn_into_use, 0);
582*38fd1498Szrj 	      else
583*38fd1498Szrj 		turn_into_use = NULL_RTX;
584*38fd1498Szrj 	    }
585*38fd1498Szrj 
586*38fd1498Szrj 	  /* Otherwise rely only on the DCE algorithm.  */
587*38fd1498Szrj 	  else if (marked_insn_p (insn))
588*38fd1498Szrj 	    continue;
589*38fd1498Szrj 
590*38fd1498Szrj 	  /* Beware that reaching a dbg counter limit here can result
591*38fd1498Szrj 	     in miscompiled file.  This occurs when a group of insns
592*38fd1498Szrj 	     must be deleted together, typically because the kept insn
593*38fd1498Szrj 	     depends on the output from the deleted insn.  Deleting
594*38fd1498Szrj 	     this insns in reverse order (both at the bb level and
595*38fd1498Szrj 	     when looking at the blocks) minimizes this, but does not
596*38fd1498Szrj 	     eliminate it, since it is possible for the using insn to
597*38fd1498Szrj 	     be top of a block and the producer to be at the bottom of
598*38fd1498Szrj 	     the block.  However, in most cases this will only result
599*38fd1498Szrj 	     in an uninitialized use of an insn that is dead anyway.
600*38fd1498Szrj 
601*38fd1498Szrj 	     However, there is one rare case that will cause a
602*38fd1498Szrj 	     miscompile: deletion of non-looping pure and constant
603*38fd1498Szrj 	     calls on a machine where ACCUMULATE_OUTGOING_ARGS is true.
604*38fd1498Szrj 	     In this case it is possible to remove the call, but leave
605*38fd1498Szrj 	     the argument pushes to the stack.  Because of the changes
606*38fd1498Szrj 	     to the stack pointer, this will almost always lead to a
607*38fd1498Szrj 	     miscompile.  */
608*38fd1498Szrj 	  if (!dbg_cnt (dce))
609*38fd1498Szrj 	    continue;
610*38fd1498Szrj 
611*38fd1498Szrj 	  if (dump_file)
612*38fd1498Szrj 	    fprintf (dump_file, "DCE: Deleting insn %d\n", INSN_UID (insn));
613*38fd1498Szrj 
614*38fd1498Szrj 	  /* Before we delete the insn we have to remove the REG_EQUAL notes
615*38fd1498Szrj 	     for the destination regs in order to avoid dangling notes.  */
616*38fd1498Szrj 	  remove_reg_equal_equiv_notes_for_defs (insn);
617*38fd1498Szrj 
618*38fd1498Szrj 	  /* If a pure or const call is deleted, this may make the cfg
619*38fd1498Szrj 	     have unreachable blocks.  We rememeber this and call
620*38fd1498Szrj 	     delete_unreachable_blocks at the end.  */
621*38fd1498Szrj 	  if (CALL_P (insn))
622*38fd1498Szrj 	    must_clean = true;
623*38fd1498Szrj 
624*38fd1498Szrj 	  if (turn_into_use)
625*38fd1498Szrj 	    {
626*38fd1498Szrj 	      /* Don't remove frame related noop moves if they cary
627*38fd1498Szrj 		 REG_CFA_RESTORE note, while we don't need to emit any code,
628*38fd1498Szrj 		 we need it to emit the CFI restore note.  */
629*38fd1498Szrj 	      PATTERN (insn)
630*38fd1498Szrj 		= gen_rtx_USE (GET_MODE (turn_into_use), turn_into_use);
631*38fd1498Szrj 	      INSN_CODE (insn) = -1;
632*38fd1498Szrj 	      df_insn_rescan (insn);
633*38fd1498Szrj 	    }
634*38fd1498Szrj 	  else
635*38fd1498Szrj 	    /* Now delete the insn.  */
636*38fd1498Szrj 	    delete_insn_and_edges (insn);
637*38fd1498Szrj 	}
638*38fd1498Szrj 
639*38fd1498Szrj   /* Deleted a pure or const call.  */
640*38fd1498Szrj   if (must_clean)
641*38fd1498Szrj     delete_unreachable_blocks ();
642*38fd1498Szrj }
643*38fd1498Szrj 
644*38fd1498Szrj 
645*38fd1498Szrj /* Go through the instructions and mark those whose necessity is not
646*38fd1498Szrj    dependent on inter-instruction information.  Make sure all other
647*38fd1498Szrj    instructions are not marked.  */
648*38fd1498Szrj 
649*38fd1498Szrj static void
650*38fd1498Szrj prescan_insns_for_dce (bool fast)
651*38fd1498Szrj {
652*38fd1498Szrj   basic_block bb;
653*38fd1498Szrj   rtx_insn *insn, *prev;
654*38fd1498Szrj   bitmap arg_stores = NULL;
655*38fd1498Szrj 
656*38fd1498Szrj   if (dump_file)
657*38fd1498Szrj     fprintf (dump_file, "Finding needed instructions:\n");
658*38fd1498Szrj 
659*38fd1498Szrj   if (!df_in_progress && ACCUMULATE_OUTGOING_ARGS)
660*38fd1498Szrj     arg_stores = BITMAP_ALLOC (NULL);
661*38fd1498Szrj 
662*38fd1498Szrj   FOR_EACH_BB_FN (bb, cfun)
663*38fd1498Szrj     {
664*38fd1498Szrj       FOR_BB_INSNS_REVERSE_SAFE (bb, insn, prev)
665*38fd1498Szrj 	if (NONDEBUG_INSN_P (insn))
666*38fd1498Szrj 	  {
667*38fd1498Szrj 	    /* Don't mark argument stores now.  They will be marked
668*38fd1498Szrj 	       if needed when the associated CALL is marked.  */
669*38fd1498Szrj 	    if (arg_stores && bitmap_bit_p (arg_stores, INSN_UID (insn)))
670*38fd1498Szrj 	      continue;
671*38fd1498Szrj 	    if (deletable_insn_p (insn, fast, arg_stores))
672*38fd1498Szrj 	      mark_nonreg_stores (PATTERN (insn), insn, fast);
673*38fd1498Szrj 	    else
674*38fd1498Szrj 	      mark_insn (insn, fast);
675*38fd1498Szrj 	  }
676*38fd1498Szrj       /* find_call_stack_args only looks at argument stores in the
677*38fd1498Szrj 	 same bb.  */
678*38fd1498Szrj       if (arg_stores)
679*38fd1498Szrj 	bitmap_clear (arg_stores);
680*38fd1498Szrj     }
681*38fd1498Szrj 
682*38fd1498Szrj   if (arg_stores)
683*38fd1498Szrj     BITMAP_FREE (arg_stores);
684*38fd1498Szrj 
685*38fd1498Szrj   if (dump_file)
686*38fd1498Szrj     fprintf (dump_file, "Finished finding needed instructions:\n");
687*38fd1498Szrj }
688*38fd1498Szrj 
689*38fd1498Szrj 
690*38fd1498Szrj /* UD-based DSE routines. */
691*38fd1498Szrj 
692*38fd1498Szrj /* Mark instructions that define artificially-used registers, such as
693*38fd1498Szrj    the frame pointer and the stack pointer.  */
694*38fd1498Szrj 
695*38fd1498Szrj static void
696*38fd1498Szrj mark_artificial_uses (void)
697*38fd1498Szrj {
698*38fd1498Szrj   basic_block bb;
699*38fd1498Szrj   struct df_link *defs;
700*38fd1498Szrj   df_ref use;
701*38fd1498Szrj 
702*38fd1498Szrj   FOR_ALL_BB_FN (bb, cfun)
703*38fd1498Szrj     FOR_EACH_ARTIFICIAL_USE (use, bb->index)
704*38fd1498Szrj       for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
705*38fd1498Szrj 	if (!DF_REF_IS_ARTIFICIAL (defs->ref))
706*38fd1498Szrj 	  mark_insn (DF_REF_INSN (defs->ref), false);
707*38fd1498Szrj }
708*38fd1498Szrj 
709*38fd1498Szrj 
710*38fd1498Szrj /* Mark every instruction that defines a register value that INSN uses.  */
711*38fd1498Szrj 
712*38fd1498Szrj static void
713*38fd1498Szrj mark_reg_dependencies (rtx_insn *insn)
714*38fd1498Szrj {
715*38fd1498Szrj   struct df_link *defs;
716*38fd1498Szrj   df_ref use;
717*38fd1498Szrj 
718*38fd1498Szrj   if (DEBUG_INSN_P (insn))
719*38fd1498Szrj     return;
720*38fd1498Szrj 
721*38fd1498Szrj   FOR_EACH_INSN_USE (use, insn)
722*38fd1498Szrj     {
723*38fd1498Szrj       if (dump_file)
724*38fd1498Szrj 	{
725*38fd1498Szrj 	  fprintf (dump_file, "Processing use of ");
726*38fd1498Szrj 	  print_simple_rtl (dump_file, DF_REF_REG (use));
727*38fd1498Szrj 	  fprintf (dump_file, " in insn %d:\n", INSN_UID (insn));
728*38fd1498Szrj 	}
729*38fd1498Szrj       for (defs = DF_REF_CHAIN (use); defs; defs = defs->next)
730*38fd1498Szrj 	if (! DF_REF_IS_ARTIFICIAL (defs->ref))
731*38fd1498Szrj 	  mark_insn (DF_REF_INSN (defs->ref), false);
732*38fd1498Szrj     }
733*38fd1498Szrj }
734*38fd1498Szrj 
735*38fd1498Szrj 
736*38fd1498Szrj /* Initialize global variables for a new DCE pass.  */
737*38fd1498Szrj 
738*38fd1498Szrj static void
739*38fd1498Szrj init_dce (bool fast)
740*38fd1498Szrj {
741*38fd1498Szrj   if (!df_in_progress)
742*38fd1498Szrj     {
743*38fd1498Szrj       if (!fast)
744*38fd1498Szrj 	{
745*38fd1498Szrj 	  df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
746*38fd1498Szrj 	  df_chain_add_problem (DF_UD_CHAIN);
747*38fd1498Szrj 	}
748*38fd1498Szrj       df_analyze ();
749*38fd1498Szrj     }
750*38fd1498Szrj 
751*38fd1498Szrj   if (dump_file)
752*38fd1498Szrj     df_dump (dump_file);
753*38fd1498Szrj 
754*38fd1498Szrj   if (fast)
755*38fd1498Szrj     {
756*38fd1498Szrj       bitmap_obstack_initialize (&dce_blocks_bitmap_obstack);
757*38fd1498Szrj       bitmap_obstack_initialize (&dce_tmp_bitmap_obstack);
758*38fd1498Szrj       can_alter_cfg = false;
759*38fd1498Szrj     }
760*38fd1498Szrj   else
761*38fd1498Szrj     can_alter_cfg = true;
762*38fd1498Szrj 
763*38fd1498Szrj   marked = sbitmap_alloc (get_max_uid () + 1);
764*38fd1498Szrj   bitmap_clear (marked);
765*38fd1498Szrj }
766*38fd1498Szrj 
767*38fd1498Szrj 
768*38fd1498Szrj /* Free the data allocated by init_dce.  */
769*38fd1498Szrj 
770*38fd1498Szrj static void
771*38fd1498Szrj fini_dce (bool fast)
772*38fd1498Szrj {
773*38fd1498Szrj   sbitmap_free (marked);
774*38fd1498Szrj 
775*38fd1498Szrj   if (fast)
776*38fd1498Szrj     {
777*38fd1498Szrj       bitmap_obstack_release (&dce_blocks_bitmap_obstack);
778*38fd1498Szrj       bitmap_obstack_release (&dce_tmp_bitmap_obstack);
779*38fd1498Szrj     }
780*38fd1498Szrj }
781*38fd1498Szrj 
782*38fd1498Szrj 
783*38fd1498Szrj /* UD-chain based DCE.  */
784*38fd1498Szrj 
785*38fd1498Szrj static unsigned int
786*38fd1498Szrj rest_of_handle_ud_dce (void)
787*38fd1498Szrj {
788*38fd1498Szrj   rtx_insn *insn;
789*38fd1498Szrj 
790*38fd1498Szrj   init_dce (false);
791*38fd1498Szrj 
792*38fd1498Szrj   prescan_insns_for_dce (false);
793*38fd1498Szrj   mark_artificial_uses ();
794*38fd1498Szrj   while (worklist.length () > 0)
795*38fd1498Szrj     {
796*38fd1498Szrj       insn = worklist.pop ();
797*38fd1498Szrj       mark_reg_dependencies (insn);
798*38fd1498Szrj     }
799*38fd1498Szrj   worklist.release ();
800*38fd1498Szrj 
801*38fd1498Szrj   if (MAY_HAVE_DEBUG_BIND_INSNS)
802*38fd1498Szrj     reset_unmarked_insns_debug_uses ();
803*38fd1498Szrj 
804*38fd1498Szrj   /* Before any insns are deleted, we must remove the chains since
805*38fd1498Szrj      they are not bidirectional.  */
806*38fd1498Szrj   df_remove_problem (df_chain);
807*38fd1498Szrj   delete_unmarked_insns ();
808*38fd1498Szrj 
809*38fd1498Szrj   fini_dce (false);
810*38fd1498Szrj   return 0;
811*38fd1498Szrj }
812*38fd1498Szrj 
813*38fd1498Szrj 
814*38fd1498Szrj namespace {
815*38fd1498Szrj 
816*38fd1498Szrj const pass_data pass_data_ud_rtl_dce =
817*38fd1498Szrj {
818*38fd1498Szrj   RTL_PASS, /* type */
819*38fd1498Szrj   "ud_dce", /* name */
820*38fd1498Szrj   OPTGROUP_NONE, /* optinfo_flags */
821*38fd1498Szrj   TV_DCE, /* tv_id */
822*38fd1498Szrj   0, /* properties_required */
823*38fd1498Szrj   0, /* properties_provided */
824*38fd1498Szrj   0, /* properties_destroyed */
825*38fd1498Szrj   0, /* todo_flags_start */
826*38fd1498Szrj   TODO_df_finish, /* todo_flags_finish */
827*38fd1498Szrj };
828*38fd1498Szrj 
829*38fd1498Szrj class pass_ud_rtl_dce : public rtl_opt_pass
830*38fd1498Szrj {
831*38fd1498Szrj public:
832*38fd1498Szrj   pass_ud_rtl_dce (gcc::context *ctxt)
833*38fd1498Szrj     : rtl_opt_pass (pass_data_ud_rtl_dce, ctxt)
834*38fd1498Szrj   {}
835*38fd1498Szrj 
836*38fd1498Szrj   /* opt_pass methods: */
837*38fd1498Szrj   virtual bool gate (function *)
838*38fd1498Szrj     {
839*38fd1498Szrj       return optimize > 1 && flag_dce && dbg_cnt (dce_ud);
840*38fd1498Szrj     }
841*38fd1498Szrj 
842*38fd1498Szrj   virtual unsigned int execute (function *)
843*38fd1498Szrj     {
844*38fd1498Szrj       return rest_of_handle_ud_dce ();
845*38fd1498Szrj     }
846*38fd1498Szrj 
847*38fd1498Szrj }; // class pass_ud_rtl_dce
848*38fd1498Szrj 
849*38fd1498Szrj } // anon namespace
850*38fd1498Szrj 
851*38fd1498Szrj rtl_opt_pass *
852*38fd1498Szrj make_pass_ud_rtl_dce (gcc::context *ctxt)
853*38fd1498Szrj {
854*38fd1498Szrj   return new pass_ud_rtl_dce (ctxt);
855*38fd1498Szrj }
856*38fd1498Szrj 
857*38fd1498Szrj 
858*38fd1498Szrj /* -------------------------------------------------------------------------
859*38fd1498Szrj    Fast DCE functions
860*38fd1498Szrj    ------------------------------------------------------------------------- */
861*38fd1498Szrj 
862*38fd1498Szrj /* Process basic block BB.  Return true if the live_in set has
863*38fd1498Szrj    changed. REDO_OUT is true if the info at the bottom of the block
864*38fd1498Szrj    needs to be recalculated before starting.  AU is the proper set of
865*38fd1498Szrj    artificial uses.  Track global substitution of uses of dead pseudos
866*38fd1498Szrj    in debug insns using GLOBAL_DEBUG.  */
867*38fd1498Szrj 
868*38fd1498Szrj static bool
869*38fd1498Szrj word_dce_process_block (basic_block bb, bool redo_out,
870*38fd1498Szrj 			struct dead_debug_global *global_debug)
871*38fd1498Szrj {
872*38fd1498Szrj   bitmap local_live = BITMAP_ALLOC (&dce_tmp_bitmap_obstack);
873*38fd1498Szrj   rtx_insn *insn;
874*38fd1498Szrj   bool block_changed;
875*38fd1498Szrj   struct dead_debug_local debug;
876*38fd1498Szrj 
877*38fd1498Szrj   if (redo_out)
878*38fd1498Szrj     {
879*38fd1498Szrj       /* Need to redo the live_out set of this block if when one of
880*38fd1498Szrj 	 the succs of this block has had a change in it live in
881*38fd1498Szrj 	 set.  */
882*38fd1498Szrj       edge e;
883*38fd1498Szrj       edge_iterator ei;
884*38fd1498Szrj       df_confluence_function_n con_fun_n = df_word_lr->problem->con_fun_n;
885*38fd1498Szrj       bitmap_clear (DF_WORD_LR_OUT (bb));
886*38fd1498Szrj       FOR_EACH_EDGE (e, ei, bb->succs)
887*38fd1498Szrj 	(*con_fun_n) (e);
888*38fd1498Szrj     }
889*38fd1498Szrj 
890*38fd1498Szrj   if (dump_file)
891*38fd1498Szrj     {
892*38fd1498Szrj       fprintf (dump_file, "processing block %d live out = ", bb->index);
893*38fd1498Szrj       df_print_word_regset (dump_file, DF_WORD_LR_OUT (bb));
894*38fd1498Szrj     }
895*38fd1498Szrj 
896*38fd1498Szrj   bitmap_copy (local_live, DF_WORD_LR_OUT (bb));
897*38fd1498Szrj   dead_debug_local_init (&debug, NULL, global_debug);
898*38fd1498Szrj 
899*38fd1498Szrj   FOR_BB_INSNS_REVERSE (bb, insn)
900*38fd1498Szrj     if (DEBUG_INSN_P (insn))
901*38fd1498Szrj       {
902*38fd1498Szrj 	df_ref use;
903*38fd1498Szrj 	FOR_EACH_INSN_USE (use, insn)
904*38fd1498Szrj 	  if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER
905*38fd1498Szrj 	      && known_eq (GET_MODE_SIZE (GET_MODE (DF_REF_REAL_REG (use))),
906*38fd1498Szrj 			   2 * UNITS_PER_WORD)
907*38fd1498Szrj 	      && !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (use))
908*38fd1498Szrj 	      && !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (use) + 1))
909*38fd1498Szrj 	    dead_debug_add (&debug, use, DF_REF_REGNO (use));
910*38fd1498Szrj       }
911*38fd1498Szrj     else if (INSN_P (insn))
912*38fd1498Szrj       {
913*38fd1498Szrj 	bool any_changed;
914*38fd1498Szrj 
915*38fd1498Szrj 	/* No matter if the instruction is needed or not, we remove
916*38fd1498Szrj 	   any regno in the defs from the live set.  */
917*38fd1498Szrj 	any_changed = df_word_lr_simulate_defs (insn, local_live);
918*38fd1498Szrj 	if (any_changed)
919*38fd1498Szrj 	  mark_insn (insn, true);
920*38fd1498Szrj 
921*38fd1498Szrj 	/* On the other hand, we do not allow the dead uses to set
922*38fd1498Szrj 	   anything in local_live.  */
923*38fd1498Szrj 	if (marked_insn_p (insn))
924*38fd1498Szrj 	  df_word_lr_simulate_uses (insn, local_live);
925*38fd1498Szrj 
926*38fd1498Szrj 	/* Insert debug temps for dead REGs used in subsequent debug
927*38fd1498Szrj 	   insns.  We may have to emit a debug temp even if the insn
928*38fd1498Szrj 	   was marked, in case the debug use was after the point of
929*38fd1498Szrj 	   death.  */
930*38fd1498Szrj 	if (debug.used && !bitmap_empty_p (debug.used))
931*38fd1498Szrj 	  {
932*38fd1498Szrj 	    df_ref def;
933*38fd1498Szrj 
934*38fd1498Szrj 	    FOR_EACH_INSN_DEF (def, insn)
935*38fd1498Szrj 	      dead_debug_insert_temp (&debug, DF_REF_REGNO (def), insn,
936*38fd1498Szrj 				      marked_insn_p (insn)
937*38fd1498Szrj 				      && !control_flow_insn_p (insn)
938*38fd1498Szrj 				      ? DEBUG_TEMP_AFTER_WITH_REG_FORCE
939*38fd1498Szrj 				      : DEBUG_TEMP_BEFORE_WITH_VALUE);
940*38fd1498Szrj 	  }
941*38fd1498Szrj 
942*38fd1498Szrj 	if (dump_file)
943*38fd1498Szrj 	  {
944*38fd1498Szrj 	    fprintf (dump_file, "finished processing insn %d live out = ",
945*38fd1498Szrj 		     INSN_UID (insn));
946*38fd1498Szrj 	    df_print_word_regset (dump_file, local_live);
947*38fd1498Szrj 	  }
948*38fd1498Szrj       }
949*38fd1498Szrj 
950*38fd1498Szrj   block_changed = !bitmap_equal_p (local_live, DF_WORD_LR_IN (bb));
951*38fd1498Szrj   if (block_changed)
952*38fd1498Szrj     bitmap_copy (DF_WORD_LR_IN (bb), local_live);
953*38fd1498Szrj 
954*38fd1498Szrj   dead_debug_local_finish (&debug, NULL);
955*38fd1498Szrj   BITMAP_FREE (local_live);
956*38fd1498Szrj   return block_changed;
957*38fd1498Szrj }
958*38fd1498Szrj 
959*38fd1498Szrj 
960*38fd1498Szrj /* Process basic block BB.  Return true if the live_in set has
961*38fd1498Szrj    changed. REDO_OUT is true if the info at the bottom of the block
962*38fd1498Szrj    needs to be recalculated before starting.  AU is the proper set of
963*38fd1498Szrj    artificial uses.  Track global substitution of uses of dead pseudos
964*38fd1498Szrj    in debug insns using GLOBAL_DEBUG.  */
965*38fd1498Szrj 
966*38fd1498Szrj static bool
967*38fd1498Szrj dce_process_block (basic_block bb, bool redo_out, bitmap au,
968*38fd1498Szrj 		   struct dead_debug_global *global_debug)
969*38fd1498Szrj {
970*38fd1498Szrj   bitmap local_live = BITMAP_ALLOC (&dce_tmp_bitmap_obstack);
971*38fd1498Szrj   rtx_insn *insn;
972*38fd1498Szrj   bool block_changed;
973*38fd1498Szrj   df_ref def;
974*38fd1498Szrj   struct dead_debug_local debug;
975*38fd1498Szrj 
976*38fd1498Szrj   if (redo_out)
977*38fd1498Szrj     {
978*38fd1498Szrj       /* Need to redo the live_out set of this block if when one of
979*38fd1498Szrj 	 the succs of this block has had a change in it live in
980*38fd1498Szrj 	 set.  */
981*38fd1498Szrj       edge e;
982*38fd1498Szrj       edge_iterator ei;
983*38fd1498Szrj       df_confluence_function_n con_fun_n = df_lr->problem->con_fun_n;
984*38fd1498Szrj       bitmap_clear (DF_LR_OUT (bb));
985*38fd1498Szrj       FOR_EACH_EDGE (e, ei, bb->succs)
986*38fd1498Szrj 	(*con_fun_n) (e);
987*38fd1498Szrj     }
988*38fd1498Szrj 
989*38fd1498Szrj   if (dump_file)
990*38fd1498Szrj     {
991*38fd1498Szrj       fprintf (dump_file, "processing block %d lr out = ", bb->index);
992*38fd1498Szrj       df_print_regset (dump_file, DF_LR_OUT (bb));
993*38fd1498Szrj     }
994*38fd1498Szrj 
995*38fd1498Szrj   bitmap_copy (local_live, DF_LR_OUT (bb));
996*38fd1498Szrj 
997*38fd1498Szrj   df_simulate_initialize_backwards (bb, local_live);
998*38fd1498Szrj   dead_debug_local_init (&debug, NULL, global_debug);
999*38fd1498Szrj 
1000*38fd1498Szrj   FOR_BB_INSNS_REVERSE (bb, insn)
1001*38fd1498Szrj     if (DEBUG_INSN_P (insn))
1002*38fd1498Szrj       {
1003*38fd1498Szrj 	df_ref use;
1004*38fd1498Szrj 	FOR_EACH_INSN_USE (use, insn)
1005*38fd1498Szrj 	  if (!bitmap_bit_p (local_live, DF_REF_REGNO (use))
1006*38fd1498Szrj 	      && !bitmap_bit_p (au, DF_REF_REGNO (use)))
1007*38fd1498Szrj 	    dead_debug_add (&debug, use, DF_REF_REGNO (use));
1008*38fd1498Szrj       }
1009*38fd1498Szrj     else if (INSN_P (insn))
1010*38fd1498Szrj       {
1011*38fd1498Szrj 	bool needed = marked_insn_p (insn);
1012*38fd1498Szrj 
1013*38fd1498Szrj 	/* The insn is needed if there is someone who uses the output.  */
1014*38fd1498Szrj 	if (!needed)
1015*38fd1498Szrj 	  FOR_EACH_INSN_DEF (def, insn)
1016*38fd1498Szrj 	    if (bitmap_bit_p (local_live, DF_REF_REGNO (def))
1017*38fd1498Szrj 		|| bitmap_bit_p (au, DF_REF_REGNO (def)))
1018*38fd1498Szrj 	      {
1019*38fd1498Szrj 		needed = true;
1020*38fd1498Szrj 		mark_insn (insn, true);
1021*38fd1498Szrj 		break;
1022*38fd1498Szrj 	      }
1023*38fd1498Szrj 
1024*38fd1498Szrj 	/* No matter if the instruction is needed or not, we remove
1025*38fd1498Szrj 	   any regno in the defs from the live set.  */
1026*38fd1498Szrj 	df_simulate_defs (insn, local_live);
1027*38fd1498Szrj 
1028*38fd1498Szrj 	/* On the other hand, we do not allow the dead uses to set
1029*38fd1498Szrj 	   anything in local_live.  */
1030*38fd1498Szrj 	if (needed)
1031*38fd1498Szrj 	  df_simulate_uses (insn, local_live);
1032*38fd1498Szrj 
1033*38fd1498Szrj 	/* Insert debug temps for dead REGs used in subsequent debug
1034*38fd1498Szrj 	   insns.  We may have to emit a debug temp even if the insn
1035*38fd1498Szrj 	   was marked, in case the debug use was after the point of
1036*38fd1498Szrj 	   death.  */
1037*38fd1498Szrj 	if (debug.used && !bitmap_empty_p (debug.used))
1038*38fd1498Szrj 	  FOR_EACH_INSN_DEF (def, insn)
1039*38fd1498Szrj 	    dead_debug_insert_temp (&debug, DF_REF_REGNO (def), insn,
1040*38fd1498Szrj 				    needed && !control_flow_insn_p (insn)
1041*38fd1498Szrj 				    ? DEBUG_TEMP_AFTER_WITH_REG_FORCE
1042*38fd1498Szrj 				    : DEBUG_TEMP_BEFORE_WITH_VALUE);
1043*38fd1498Szrj       }
1044*38fd1498Szrj 
1045*38fd1498Szrj   dead_debug_local_finish (&debug, NULL);
1046*38fd1498Szrj   df_simulate_finalize_backwards (bb, local_live);
1047*38fd1498Szrj 
1048*38fd1498Szrj   block_changed = !bitmap_equal_p (local_live, DF_LR_IN (bb));
1049*38fd1498Szrj   if (block_changed)
1050*38fd1498Szrj     bitmap_copy (DF_LR_IN (bb), local_live);
1051*38fd1498Szrj 
1052*38fd1498Szrj   BITMAP_FREE (local_live);
1053*38fd1498Szrj   return block_changed;
1054*38fd1498Szrj }
1055*38fd1498Szrj 
1056*38fd1498Szrj 
1057*38fd1498Szrj /* Perform fast DCE once initialization is done.  If WORD_LEVEL is
1058*38fd1498Szrj    true, use the word level dce, otherwise do it at the pseudo
1059*38fd1498Szrj    level.  */
1060*38fd1498Szrj 
1061*38fd1498Szrj static void
1062*38fd1498Szrj fast_dce (bool word_level)
1063*38fd1498Szrj {
1064*38fd1498Szrj   int *postorder = df_get_postorder (DF_BACKWARD);
1065*38fd1498Szrj   int n_blocks = df_get_n_blocks (DF_BACKWARD);
1066*38fd1498Szrj   /* The set of blocks that have been seen on this iteration.  */
1067*38fd1498Szrj   bitmap processed = BITMAP_ALLOC (&dce_blocks_bitmap_obstack);
1068*38fd1498Szrj   /* The set of blocks that need to have the out vectors reset because
1069*38fd1498Szrj      the in of one of their successors has changed.  */
1070*38fd1498Szrj   bitmap redo_out = BITMAP_ALLOC (&dce_blocks_bitmap_obstack);
1071*38fd1498Szrj   bitmap all_blocks = BITMAP_ALLOC (&dce_blocks_bitmap_obstack);
1072*38fd1498Szrj   bool global_changed = true;
1073*38fd1498Szrj 
1074*38fd1498Szrj   /* These regs are considered always live so if they end up dying
1075*38fd1498Szrj      because of some def, we need to bring the back again.  Calling
1076*38fd1498Szrj      df_simulate_fixup_sets has the disadvantage of calling
1077*38fd1498Szrj      bb_has_eh_pred once per insn, so we cache the information
1078*38fd1498Szrj      here.  */
1079*38fd1498Szrj   bitmap au = &df->regular_block_artificial_uses;
1080*38fd1498Szrj   bitmap au_eh = &df->eh_block_artificial_uses;
1081*38fd1498Szrj   int i;
1082*38fd1498Szrj   struct dead_debug_global global_debug;
1083*38fd1498Szrj 
1084*38fd1498Szrj   prescan_insns_for_dce (true);
1085*38fd1498Szrj 
1086*38fd1498Szrj   for (i = 0; i < n_blocks; i++)
1087*38fd1498Szrj     bitmap_set_bit (all_blocks, postorder[i]);
1088*38fd1498Szrj 
1089*38fd1498Szrj   dead_debug_global_init (&global_debug, NULL);
1090*38fd1498Szrj 
1091*38fd1498Szrj   while (global_changed)
1092*38fd1498Szrj     {
1093*38fd1498Szrj       global_changed = false;
1094*38fd1498Szrj 
1095*38fd1498Szrj       for (i = 0; i < n_blocks; i++)
1096*38fd1498Szrj 	{
1097*38fd1498Szrj 	  int index = postorder[i];
1098*38fd1498Szrj 	  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, index);
1099*38fd1498Szrj 	  bool local_changed;
1100*38fd1498Szrj 
1101*38fd1498Szrj 	  if (index < NUM_FIXED_BLOCKS)
1102*38fd1498Szrj 	    {
1103*38fd1498Szrj 	      bitmap_set_bit (processed, index);
1104*38fd1498Szrj 	      continue;
1105*38fd1498Szrj 	    }
1106*38fd1498Szrj 
1107*38fd1498Szrj 	  if (word_level)
1108*38fd1498Szrj 	    local_changed
1109*38fd1498Szrj 	      = word_dce_process_block (bb, bitmap_bit_p (redo_out, index),
1110*38fd1498Szrj 					&global_debug);
1111*38fd1498Szrj 	  else
1112*38fd1498Szrj 	    local_changed
1113*38fd1498Szrj 	      = dce_process_block (bb, bitmap_bit_p (redo_out, index),
1114*38fd1498Szrj 				   bb_has_eh_pred (bb) ? au_eh : au,
1115*38fd1498Szrj 				   &global_debug);
1116*38fd1498Szrj 	  bitmap_set_bit (processed, index);
1117*38fd1498Szrj 
1118*38fd1498Szrj 	  if (local_changed)
1119*38fd1498Szrj 	    {
1120*38fd1498Szrj 	      edge e;
1121*38fd1498Szrj 	      edge_iterator ei;
1122*38fd1498Szrj 	      FOR_EACH_EDGE (e, ei, bb->preds)
1123*38fd1498Szrj 		if (bitmap_bit_p (processed, e->src->index))
1124*38fd1498Szrj 		  /* Be tricky about when we need to iterate the
1125*38fd1498Szrj 		     analysis.  We only have redo the analysis if the
1126*38fd1498Szrj 		     bitmaps change at the top of a block that is the
1127*38fd1498Szrj 		     entry to a loop.  */
1128*38fd1498Szrj 		  global_changed = true;
1129*38fd1498Szrj 		else
1130*38fd1498Szrj 		  bitmap_set_bit (redo_out, e->src->index);
1131*38fd1498Szrj 	    }
1132*38fd1498Szrj 	}
1133*38fd1498Szrj 
1134*38fd1498Szrj       if (global_changed)
1135*38fd1498Szrj 	{
1136*38fd1498Szrj 	  /* Turn off the RUN_DCE flag to prevent recursive calls to
1137*38fd1498Szrj 	     dce.  */
1138*38fd1498Szrj 	  int old_flag = df_clear_flags (DF_LR_RUN_DCE);
1139*38fd1498Szrj 
1140*38fd1498Szrj 	  /* So something was deleted that requires a redo.  Do it on
1141*38fd1498Szrj 	     the cheap.  */
1142*38fd1498Szrj 	  delete_unmarked_insns ();
1143*38fd1498Szrj 	  bitmap_clear (marked);
1144*38fd1498Szrj 	  bitmap_clear (processed);
1145*38fd1498Szrj 	  bitmap_clear (redo_out);
1146*38fd1498Szrj 
1147*38fd1498Szrj 	  /* We do not need to rescan any instructions.  We only need
1148*38fd1498Szrj 	     to redo the dataflow equations for the blocks that had a
1149*38fd1498Szrj 	     change at the top of the block.  Then we need to redo the
1150*38fd1498Szrj 	     iteration.  */
1151*38fd1498Szrj 	  if (word_level)
1152*38fd1498Szrj 	    df_analyze_problem (df_word_lr, all_blocks, postorder, n_blocks);
1153*38fd1498Szrj 	  else
1154*38fd1498Szrj 	    df_analyze_problem (df_lr, all_blocks, postorder, n_blocks);
1155*38fd1498Szrj 
1156*38fd1498Szrj 	  if (old_flag & DF_LR_RUN_DCE)
1157*38fd1498Szrj 	    df_set_flags (DF_LR_RUN_DCE);
1158*38fd1498Szrj 
1159*38fd1498Szrj 	  prescan_insns_for_dce (true);
1160*38fd1498Szrj 	}
1161*38fd1498Szrj     }
1162*38fd1498Szrj 
1163*38fd1498Szrj   dead_debug_global_finish (&global_debug, NULL);
1164*38fd1498Szrj 
1165*38fd1498Szrj   delete_unmarked_insns ();
1166*38fd1498Szrj 
1167*38fd1498Szrj   BITMAP_FREE (processed);
1168*38fd1498Szrj   BITMAP_FREE (redo_out);
1169*38fd1498Szrj   BITMAP_FREE (all_blocks);
1170*38fd1498Szrj }
1171*38fd1498Szrj 
1172*38fd1498Szrj 
1173*38fd1498Szrj /* Fast register level DCE.  */
1174*38fd1498Szrj 
1175*38fd1498Szrj static unsigned int
1176*38fd1498Szrj rest_of_handle_fast_dce (void)
1177*38fd1498Szrj {
1178*38fd1498Szrj   init_dce (true);
1179*38fd1498Szrj   fast_dce (false);
1180*38fd1498Szrj   fini_dce (true);
1181*38fd1498Szrj   return 0;
1182*38fd1498Szrj }
1183*38fd1498Szrj 
1184*38fd1498Szrj 
1185*38fd1498Szrj /* Fast byte level DCE.  */
1186*38fd1498Szrj 
1187*38fd1498Szrj void
1188*38fd1498Szrj run_word_dce (void)
1189*38fd1498Szrj {
1190*38fd1498Szrj   int old_flags;
1191*38fd1498Szrj 
1192*38fd1498Szrj   if (!flag_dce)
1193*38fd1498Szrj     return;
1194*38fd1498Szrj 
1195*38fd1498Szrj   timevar_push (TV_DCE);
1196*38fd1498Szrj   old_flags = df_clear_flags (DF_DEFER_INSN_RESCAN + DF_NO_INSN_RESCAN);
1197*38fd1498Szrj   df_word_lr_add_problem ();
1198*38fd1498Szrj   init_dce (true);
1199*38fd1498Szrj   fast_dce (true);
1200*38fd1498Szrj   fini_dce (true);
1201*38fd1498Szrj   df_set_flags (old_flags);
1202*38fd1498Szrj   timevar_pop (TV_DCE);
1203*38fd1498Szrj }
1204*38fd1498Szrj 
1205*38fd1498Szrj 
1206*38fd1498Szrj /* This is an internal call that is used by the df live register
1207*38fd1498Szrj    problem to run fast dce as a side effect of creating the live
1208*38fd1498Szrj    information.  The stack is organized so that the lr problem is run,
1209*38fd1498Szrj    this pass is run, which updates the live info and the df scanning
1210*38fd1498Szrj    info, and then returns to allow the rest of the problems to be run.
1211*38fd1498Szrj 
1212*38fd1498Szrj    This can be called by elsewhere but it will not update the bit
1213*38fd1498Szrj    vectors for any other problems than LR.  */
1214*38fd1498Szrj 
1215*38fd1498Szrj void
1216*38fd1498Szrj run_fast_df_dce (void)
1217*38fd1498Szrj {
1218*38fd1498Szrj   if (flag_dce)
1219*38fd1498Szrj     {
1220*38fd1498Szrj       /* If dce is able to delete something, it has to happen
1221*38fd1498Szrj 	 immediately.  Otherwise there will be problems handling the
1222*38fd1498Szrj 	 eq_notes.  */
1223*38fd1498Szrj       int old_flags =
1224*38fd1498Szrj 	df_clear_flags (DF_DEFER_INSN_RESCAN + DF_NO_INSN_RESCAN);
1225*38fd1498Szrj 
1226*38fd1498Szrj       df_in_progress = true;
1227*38fd1498Szrj       rest_of_handle_fast_dce ();
1228*38fd1498Szrj       df_in_progress = false;
1229*38fd1498Szrj 
1230*38fd1498Szrj       df_set_flags (old_flags);
1231*38fd1498Szrj     }
1232*38fd1498Szrj }
1233*38fd1498Szrj 
1234*38fd1498Szrj 
1235*38fd1498Szrj /* Run a fast DCE pass.  */
1236*38fd1498Szrj 
1237*38fd1498Szrj void
1238*38fd1498Szrj run_fast_dce (void)
1239*38fd1498Szrj {
1240*38fd1498Szrj   if (flag_dce)
1241*38fd1498Szrj     rest_of_handle_fast_dce ();
1242*38fd1498Szrj }
1243*38fd1498Szrj 
1244*38fd1498Szrj 
1245*38fd1498Szrj namespace {
1246*38fd1498Szrj 
1247*38fd1498Szrj const pass_data pass_data_fast_rtl_dce =
1248*38fd1498Szrj {
1249*38fd1498Szrj   RTL_PASS, /* type */
1250*38fd1498Szrj   "rtl_dce", /* name */
1251*38fd1498Szrj   OPTGROUP_NONE, /* optinfo_flags */
1252*38fd1498Szrj   TV_DCE, /* tv_id */
1253*38fd1498Szrj   0, /* properties_required */
1254*38fd1498Szrj   0, /* properties_provided */
1255*38fd1498Szrj   0, /* properties_destroyed */
1256*38fd1498Szrj   0, /* todo_flags_start */
1257*38fd1498Szrj   TODO_df_finish, /* todo_flags_finish */
1258*38fd1498Szrj };
1259*38fd1498Szrj 
1260*38fd1498Szrj class pass_fast_rtl_dce : public rtl_opt_pass
1261*38fd1498Szrj {
1262*38fd1498Szrj public:
1263*38fd1498Szrj   pass_fast_rtl_dce (gcc::context *ctxt)
1264*38fd1498Szrj     : rtl_opt_pass (pass_data_fast_rtl_dce, ctxt)
1265*38fd1498Szrj   {}
1266*38fd1498Szrj 
1267*38fd1498Szrj   /* opt_pass methods: */
1268*38fd1498Szrj   virtual bool gate (function *)
1269*38fd1498Szrj     {
1270*38fd1498Szrj       return optimize > 0 && flag_dce && dbg_cnt (dce_fast);
1271*38fd1498Szrj     }
1272*38fd1498Szrj 
1273*38fd1498Szrj   virtual unsigned int execute (function *)
1274*38fd1498Szrj     {
1275*38fd1498Szrj       return rest_of_handle_fast_dce ();
1276*38fd1498Szrj     }
1277*38fd1498Szrj 
1278*38fd1498Szrj }; // class pass_fast_rtl_dce
1279*38fd1498Szrj 
1280*38fd1498Szrj } // anon namespace
1281*38fd1498Szrj 
1282*38fd1498Szrj rtl_opt_pass *
1283*38fd1498Szrj make_pass_fast_rtl_dce (gcc::context *ctxt)
1284*38fd1498Szrj {
1285*38fd1498Szrj   return new pass_fast_rtl_dce (ctxt);
1286*38fd1498Szrj }
1287